C - assert宏,输出传入的值



在我们的C代码库中,我们有断言宏,如:

ASSERT3(x, ==, y)      // x=0, y=1 results in "main.c:45: 'x == y' (0 == 1) is untrue"
ASSERT(x == y)         // x=0, y=1 results in "main.c:45: 'x == y' is untrue"

显然,当您在失败后试图调试某些东西时,ASSERT3表单更有帮助,因为它告诉您变量的值是什么。

然而,当您需要执行更复杂的断言时(特别是那些包含||的断言,因为您可以将具有&&的断言拆分为多个断言),例如ASSERT(x == y || y != 0 || x == 2),您就不能再利用令人惊叹的ASSERT3格式了。显然,我可以构建一个像ASSERT11(x, ==, y, ||, y, !=, 0, ||, x, ==, 2)这样的宏,但理想情况下,我想创建一个可以处理可变数量的参数的宏,并找出自己要打印的内容。要做到这一点,我认为我需要宏过滤掉只是逻辑运算符的参数,这样它就不会试图打印它们的值——有什么方法可以做到这一点吗?

我曾经有过这种感觉,也有过这样的想法,但事实证明断言是用于不应该发生的事情的,因此为它们提供花哨的输出实际上没有意义。您要寻找的是在不满足这些条件时打印的调试消息,因此您应该这样编码:

if (!condition) {
    DEBUG(whatever); /* or however your ASSERT() macro prints */
    PANIC();         /* or however your ASSERT() macro aborts */
}

在这种情况下,我实际上认为代码更容易编写,更容易阅读,并且明显比您最终将使用的复杂的ASSERT语句更可靠。更不用说,一旦断言变得如此复杂,肯定还有其他重要的相关信息实际上不在assert语句中。

这可能不值得您投入精力,但我会给您一个大致的轮廓,您可以决定。

理论上可以用可变宏

来完成
#define UBER_ASSERT(...) uberAssert( __FILE__, __LINE__, __VA_ARGS__ )

和可变函数

void uberAssert( char *filename, int linenumber, char *format, ... )

典型用法如下

UBER_ASSERT( "%1d == %2d || %2d != 0 || %1d == 2", x, y );

和一个最小的例子看起来像这样

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define UBER_ASSERT(...) uberAssert( __FILE__, __LINE__, __VA_ARGS__ )
int evaluateExpression( char *format, va_list args )
{
    int x = va_arg( args, int );
    int y = va_arg( args, int );
    printf( "evaluating "%s" with x=%d y=%dn", format, x, y );
    return 0;
}
void displayExpression( char *format, va_list args )
{
    int x = va_arg( args, int );
    int y = va_arg( args, int );
    printf( "%s with x=%d y=%dn", format, x, y );
}
void uberAssert( char *filename, int linenumber, char *format, ... )
{
    va_list args, args2;
    va_start( args, format );
    va_copy( args2, args );
    if ( !evaluateExpression( format, args ) )
    {
        printf( "%s:%d: ", filename, linenumber );
        displayExpression( format, args2 );
        abort();
    }
    va_end( args );
    va_end( args2 );
}
int main( void )
{
    int x = 3;
    int y = 5;
    UBER_ASSERT( "%1d==%2d || %2d!=0 || %1d==2", x, y );
}
困难的部分是编写表达式求值器和表达式显示函数,我把它留给读者作为练习。

最新更新