GCC编译器和Clang编译器的行为不同,其中Clang允许在定义之前声明static
变量,而GCC编译器将声明(或“临时定义”)视为定义。
我相信这是GCC中的错误,但是抱怨它并打开错误报告并不能解决我今天(或昨天)需要在GCC上编译代码的问题...
这里有个简单的例子:
static struct example_s { int i; } example[];
int main(void) {
fprintf(stderr, "Number: %d\n", example[0].i);
return 0;
}
static struct example_s example[] = {{1}, {2}, {3}};
使用Clang编译器,该程序将编译并打印出:
Number: 1
但是,使用GCC,代码将无法编译,并且出现以下错误(忽略行号):
src/main2.c:26:36: error: array size missing in ‘example’
static struct example_s { int i; } example[];
^~~~~~~
src/main2.c:33:25: error: conflicting types for ‘example’
static struct example_s example[256] = {{1}, {2}, {3}};
^~~~~~~
src/main2.c:26:36: note: previous declaration of ‘example’ was here
static struct example_s { int i; } example[];
这是GCC错误还是Clang错误?谁知道。也许如果您是其中一个团队,您可以决定。
对于我来说,在静态定义之前的静态声明应该是(AFAIK)有效的C(根据C11标准的6.9.2节,是一个“临时定义”)...所以我假设存在一些GCC中的扩展名使事情变得混乱了。
是否可以添加pragma
或其他指令以确保GCC将声明视为声明?
答案 0 :(得分:3)
C11草案在§6.9.2外部对象定义中具有以下内容:
3如果对象标识符的声明是临时定义,并且具有 内部链接,声明的类型不得为不完整的类型
我读这句话的意思是,代码中的第一行包含未指定长度的数组,因此不能作为适当的临时定义。不知道那会是什么,但这可以解释GCC的第一条消息。
答案 1 :(得分:1)
编辑:显然,由于-Wpedantic
标志,gcc引发了错误,该标志(出于某种晦涩的原因)除了警告外还添加了错误(请参见:godbolt.org并删除要编译的标志。
¯\_(ツ)_/¯
一个可能的(虽然不是DRY)答案是将数组长度添加到初始声明中(在涉及C11的情况下使用暂定声明创建完整的类型)...即:
static struct example_s { int i; } example[3];
int main(void) {
fprintf(stderr, "Number: %d\n", example[0].i);
return 0;
}
static struct example_s example[3] = {{1}, {2}, {3}};
这很烦人,因为它引入了维护问题,但这是一个可行的临时解决方案。