请考虑以下代码:
const int g_foo = 1;
// (1):
_Static_assert(g_foo > 0, "g_foo > 0"); // error: expression in static assertion is not constant.
_Static_assert(g_foo > 2, "g_foo > 2"); // error: expression in static assertion is not constant.
void Foo(void) {
const int foo = 1;
// (2):
_Static_assert(foo > 0, "foo > 0"); // No issue.
_Static_assert(foo > 2, "foo > 2"); // error: static assertion failed: "foo > 2"
// (3):
_Static_assert(g_foo > 0, "g_foo > 0"); // No issue.
_Static_assert(g_foo > 2, "g_foo > 2"); // error: static assertion failed: "g_foo > 2"
}
在GCC版本7.4.0中使用gcc -std=c11 -O3 test.c
进行编译会产生指示的错误消息。也可以找到使用GCC 9.2的Compiler Explorer示例here。
[从标有(2)的静态断言开始,我们使用的是const限定的局部变量。在此优化级别,const int foo = 1;
被优化,因此不评估初始化程序。据我了解,这根据ISO / IEC 9899:2011 * 6.6.3将其归类为常量表达式,并允许其由_Static_assert
**求值。到目前为止一切顺利。
标记为(1)的静态断言尝试评估包含全局变量g_foo
的表达式,但是事实是,全局变量在内存中分配了空间,这意味着它们实际上需要初始化。此评估会自动取消他们成为常量表达式的资格,因此GCC会投诉。
然后我们转到(3)。突然,在全局范围内失败的静态断言开始起作用。发生了什么事?
*很遗憾,我使用的是2010-12-02 committee draft,而不是最终发布的规格。
**另外,在这个问题中,使用非零优化级别非常重要。使用-O0
时,变量foo
实际上是用文字1
实例化的。但是,这不再是常量表达式,并且使用foo
的静态声明会因“静态声明中的表达式不是常量”而开始失败。
编辑(2019-11-04):
*(int *)&g_foo = -1;
-这是未定义的行为,并且分散了主要问题的注意力。const
限定变量的多余讽刺。请考虑以下代码:const int g_foo = 1; //(1):_Static_assert(g_foo> 0,“ g_foo> 0”); //错误:静态断言中的表达式不是常量。 _Static_assert(g_foo> 2,“ g_foo ...
*(int *)&g_foo = -1;
是明确的未定义行为,根据C17 6.7.3 / 6: