Кілька пояснень. Перший - загальний, другий - специфічний для макросів препроцесора C з параметрами:
Управління потоком
Я бачив, що це використовується в простому коді С. В основному, це більш безпечна версія goto, оскільки ви можете вийти з нього, і вся пам'ять очищається належним чином.
Чому щось подібне goto
було б добре? Ну, якщо у вас є код, де майже кожен рядок може повернути помилку, але вам потрібно реагувати на них однаково (наприклад, передавши помилку своєму абонентові після очищення), як правило, це читабельніше уникати if( error ) { /* cleanup and error string generation and return here */ }
як це дозволяє уникнути дублювання коду очищення.
Однак у C ++ у вас є винятки + RAII саме для цієї мети, тому я вважаю це поганим стилем кодування.
Перевірка з комою
Якщо ви забудете крапку з комою після виклику макросу, подібного до функції, аргументи можуть скоротитися небажаним чином і скомпілюватись у дійсний синтаксис. Уявіть собі макрос
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
Це випадково називається як
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
"Інше" вважатиметься асоційованим із тим gDebugModeOn
, коли foo
це єfalse
, точний реверс задуманого будуть.
Надання області для тимчасових змінних.
Оскільки do / while має фігурні дужки, тимчасові змінні мають чітко визначену область, з якої вони не можуть уникнути.
Уникання попереджень про "можливо небажану крапку з комою"
Деякі макроси активуються лише у складах налагодження. Ви визначаєте їх як:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
Тепер, якщо ви використовуєте це у версії версії всередині умовного, він компілюється в
if( foo )
;
Багато компіляторів бачать це як те саме, що
if( foo );
Що часто пишеться випадково. Так ви отримуєте попередження. Do {} while (false) приховує це від компілятора і приймається ним як ознака того, що ви дійсно не хочете нічого робити тут.
Уникайте захоплення ліній умовними умовами
Макрос із попереднього прикладу:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
Тепер, у налагодженнях налагодження, оскільки ми також звично включали крапку з комою, це складеться чудово. Однак у складанні випуску це раптом перетворюється на:
if( foo )
doSomething();
Або більш чітко відформатований
if( foo )
doSomething();
Що зовсім не те, що було призначено. Додавання do {...} while (false) навколо макроса перетворює відсутню крапку з комою в помилку компіляції.
Що це означає для ОП?
Загалом, ви хочете використовувати винятки в C ++ для обробки помилок, а шаблони замість макросів. Однак у дуже рідкісному випадку, коли вам все-таки потрібні макроси (наприклад, при генерації імен класів за допомогою вставки лексеми) або обмежуються простою C, це корисна модель.