在初始化全局变量时使用断言宏

Using the assert macro while global variables are initialized

本文关键字:断言 初始化 全局变量      更新时间:2023-10-16

在下面的代码中,第一个assert不编译,因为至少在MSVC2015RC中,它本质上被定义为assert(expression) (void)(!!(expression))

int x = 1;
assert( x == 1 );
void foo()
{
    assert( x == 1 );
}

错误消息是

C2062 类型"空"意外

第二个断言编译没有问题,但除非调用foo()否则不会执行。我想在初始化全局变量时使用assert。有什么解决方法吗?

这里有两个问题。

首先,只有声明(例如变量、类、函数)可以进入全局范围。 assert()不是宣言,这就是为什么你不能在那里做。

这可能会导致一种解决方法,只需将其推入声明中,例如:

int x = 1;
namespace assert_x_is_1 {
    bool _ = (assert(x == 1), true);
}

在 gcc 上,上面的编译很好,如果 x 不是 1,就会断言。然而,在 clang 上,这导致了第二个问题:assert()真的想在函数中使用 - 它使用仅在函数中定义的宏。

因此,为此,您可以编写一个类声明:

#define ASSERT_CLASS2(expr, ctr) namespace assert##ctr { struct Asserter { Asserter() { assert(expr); } } s; }
#define ASSERT_CLASS(expr) ASSERT_CLASS2(expr, __COUNTER__)
int x = 1;
ASSERT_CLASS(x == 1);

这将在半匿名命名空间中创建一个全局变量,该命名空间在其构造函数中将断言表达式。这适用于 clang 和 gcc。

在 C/C++ 中,语句如

x==1

不能写超出功能

assert( x == 1 );

将在预编译期间替换

(void)(!!(x==1));

这是一个语句,不能写在函数定义之外