断言宏打印

时间:2015-07-23 16:55:30

标签: c macros assert c-preprocessor

在我们的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)这样的宏,但理想情况下我想创建一个宏,它可以处理可变数量的参数并找出要在其上打印的内容拥有。要做到这一点,我认为我需要宏来过滤出只是逻辑运算符的参数,这样它就不会尝试打印它们的值 - 有没有办法做到这一点?

2 个答案:

答案 0 :(得分:0)

我已经有了这样的感觉和想法,但事实证明,断言是为了永远不会发生的事情,所以为它们提供奇特的输出并不是真的有意义。您正在寻找的是在不满足这些条件时打印的调试消息,因此您应该以这样的方式编写代码:

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

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

答案 1 :(得分:0)

这可能不值得你付出努力,但我会给你一般大纲,你可以决定。

理论上可以使用可变参数宏

#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=%d\n", 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=%d\n", 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 );
}

困难的部分是编写表达式赋值器和表达式显示函数,并将其作为练习留给读者。