使用GCC编译时,在定义静态数组之前先声明一个静态数组

时间:2019-03-11 20:12:10

标签: c gcc

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将声明视为声明?

2 个答案:

答案 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}};

这很烦人,因为它引入了维护问题,但这是一个可行的临时解决方案。