Описываются 5 засадных моментов макросов и не только применительно к написанию собственного макроса ASSERT. Для тех, кто писал собственный ASSERT или логирование с примененением макросов, ничего особого нового не будет, иначе — must read.
http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
Здравствуйте, remark, Вы писали:
R>Описываются 5 засадных моментов макросов и не только применительно к написанию собственного макроса ASSERT. Для тех, кто писал собственный ASSERT или логирование с примененением макросов, ничего особого нового не будет, иначе — must read.
R>http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
R>
А что, там где он трюки делает с do while(0) нельзя было просто блок использовать?
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>А что, там где он трюки делает с do while(0) нельзя было просто блок использовать?
В ассертах можно, а вот когда тебе нужно какоe-нть логирование (т.е. если ты хочешь писать MY_LOG_MACRO << "test"
, придется извращаться примерно так:
if ( !log_enabled) ; else
блин, сколько там дальше мути развели в борьбе с предупреждениями компилятора из-за этого while(0). вот это сила!
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>блин, сколько там дальше мути развели в борьбе с предупреждениями компилятора из-за этого while(0). вот это сила!
Да, это тоже хорошая тема
Я обычно пишу или "while ((void)0, 0)" или "while (identity(0))", тогда и студия и гцц не ругаются на константые условия и бессмысленные выражения.
R>Я обычно пишу или "while ((void)0, 0)" или "while (identity(0))", тогда и студия и гцц не ругаются на константые условия и бессмысленные выражения.
А зачем тебе такие while ?
Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>Я обычно пишу или "while ((void)0, 0)" или "while (identity(0))", тогда и студия и гцц не ругаются на константые условия и бессмысленные выражения.
L_L>А зачем тебе такие while ?
Обычно это бывает в виде if-ов в шаблонных функциях. Суть одна — как побороть варнинг о константном условии (которое в шаблонной функции не такое уж и константное).
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>А что, там где он трюки делает с do while(0) нельзя было просто блок использовать?
do-while — это незаконченный стейтмент, после него, как и после выражения, нужно ставить ';'
А блок {...} — законченный стейтмент, лишняя точка с запятой будет воспринята как ещё один, пустой, стейтмент.
Это аукнется в двух местах
— варнинг про пустой стейтмент
— путаница между стейтментами if()... и if()...else...
Если нет нужды в какой-то хитрой логике переходов, то можно привести макрос к выражению
#define UNUSED(expr) ((void)sizeof(expr))
inline void Assert(const char* file, int line, const char* expr, bool cond)
{.....}
#ifdef USE_ASSERTS
#define ASSERT(expr) Assert( __FILE__, __LINE__, #expr, !!(expr) )
#else
#define ASSERT(expr) UNUSED(expr)
#endif
Но тогда отладчик остановится не в коде, а в определении Assert
Против этого можно использовать операторы ветвления и/или следования
#define ASSERT(expr) \
( \
(expr) \
? (void)0 /* допущение выполнено - отлично! */ \
: \
DebugPrompt(__FILE__,__LINE__,#expr) /* допущение не выполнено - покажем еггог */ \
? (void)0 : /* пользователь нажал "пролоджить" - продолжаем */ \
: (void)DebugBreak() /* точка остановки */ \
) \
//endmacro
Козырно то, что такой ASSERT можно использовать не как стейтмент, но и как выражение в составе других выражений и стейтментов.
Естественно, что он имеет смысл в составе операторов, расставляющих точки останова (?: , && ||)- иначе получим неспецифицированное, а то и неопределённое, поведение.
// правильно
for(x = 0; ASSERT(x>=0&&x<n), x!=n; ++x) { ..... ++x; ..... --x; ..... }
x = (ASSERT(y>0), y + z) ; // правильно
x = (ASSERT(y>0), y) + z ; // сомнительно
x = (ASSERT(y>0), y) + f(y); // неправильно
if((ASSERT(x),true) && f(x)) ..... // правильно
if((ASSERT(x),0 ) + f(x)) ..... // неправильно
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Здравствуйте, Basil2, Вы писали:
B>Здравствуйте, Alexander G, Вы писали:
AG>>Чем-то
AG>>do { if (!(x)) f(x); } while(0)
AG>>лучше
AG>> if (x) {} else f(x)
AG>>?
B>А если f(x) несколько?