Почему бы не использовать стандартный интерфейс assert
и включить целое выражение?
#define assert(EXPR) \
if (!(EXPR)) \
{asprintf(&astrbuf, "\nAssert error %s %d %s\n",__FILE__, __LINE__, #EXPR); \
asserted(); \
}
... используя оператор строкового макроса #
.
Кстати, почему половина вашего кода в макросе, а другая половина в функции asserted
? Почему бы не сделать все это в одном месте?
#define assert(EXPR) \
if (!(EXPR)) \
{ \
asserted(__FILE__, __LINE__, #EXPR); \
}
с
void asserted(const char *file, int line, const char *expr) {
char *astrbuf;
asprintf(&astrbuf, "%s: %d: assertion failed: %s\n", file, line, expr);
dprint("%s", astrbuf);
...
}
Теперь вам больше не нужна глобальная переменная.
Есть еще одна потенциальная проблема. Если вы используете свой макрос следующим образом:
if (foo())
assert(x > 42);
else
bar();
... часть else bar();
будет прикреплена к оператору if
, скрытому в assert
, а не к внешнему if
. Чтобы это исправить, вы можете обернуть все это в цикл do
while
:
#define assert(EXPR) \
do { \
if (!(EXPR)) { \
asserted(__FILE__, __LINE__, #EXPR); \
} \
} while (0)
Или, альтернативно, убедитесь, что весь макрос расширяется до одного выражения:
#define assert(EXPR) \
((void)((EXPR) || (asserted(__FILE__, __LINE__, #EXPR), 0)))
Конечно, вы также можете поместить условную логику в функцию:
#define assert(EXPR) asserted(!!(EXPR), __FILE__, __LINE__, #expr)
void asserted(int cond, const char *file, int line, const char *expr) {
if (cond) {
return;
}
...
}