首页 > 解决方案 > Better Assert in C

问题描述

Sometimes I have to send the result of an assert over canbus, sometimes its local. I use C only, Embitz compiler using GCC, STM32F407 or STM32F103. My present assert is: .h file:

extern char *astrbuf;
#define assert(left,operator,right)\
if(!((left) operator (right))) \
 {asprintf(&astrbuf,"\nAssert error %s %d %ld %ld\n",__FILE__, __LINE__,\
  (u32)(left),(u32)(right));\
  asserted();\
 }

.c file:

void asserted(void)
{ dprint("%s",astrbuf);

followed by the display code or canbus code. Example: assert(millis,<,maxtime); This works very well, but will be better if the operator can be indicated. I simply do not see how to display or send the operator, which can be ==, <, or >.

标签: cassert

解决方案


为什么不使用标准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;
    }
    ...
}

推荐阅读