23

有一些使用 VLA(可变长度数组)的奇怪代码被 gcc 4.6 视为有效 C(C99,C11):

$ cat a.c
int main(int argc,char**argv)
{
  struct args_t{
     int a;
     int params[argc];        // << Wat?
                        // VLA in the middle of some struct, between other fields
     int b;
  } args;

  args.b=0;

  for(args.a=0;args.a<argc;args.a++)
  {
    args.params[args.a]=argv[0][0];
    args.b++;
  }
  return args.b;
}

此代码编译时没有警告:

$ gcc-4.6 -Wall -std=c99 a.c && echo $?
0
$ ./a.out ; echo $?
1
$ ./a.out 2; echo $?
2
$ ./a.out 2 3; echo $?
3

同样适用于-std=c1x

$ gcc-4.6 -Wall -std=c1x a.c && echo $?
0

但这不适用于英特尔 C 编译器或 Clang+LLVM:

$ icc a.c -o a.icc
a.c(5): warning #1361: variable-length array field type will be treated as zero-length array field type
       int params[argc];
                  ^
$ ./a.icc; echo $?
47

$ clang a.c -o a.clang
a.c:5:10: error: fields must have a constant size: 'variable length array in structure' extension will never be supported
     int params[argc];
         ^
1 error generated.

所以:

  1. 为什么这被 GCC 认为是有效的?
  2. 如果它是 GCC 的扩展,它在哪里描述?
  3. 它在 C99 和 C11 ISO 标准中有效吗?
4

3 回答 3

9

GCC does not allow it, compile with -std=c99 -pedantic-errors. A VLA inside a struct is apparently a (poorly documented) non-standard GNU C feature. See this.

于 2013-01-31T15:48:26.607 回答
4

标准非常清楚,VLA 不允许在 a 中使用struct

6.7.2.1 结构和联合说明符

9 - 结构或联合的成员可以具有除可变修改类型之外的任何完整对象类型。[...]

可变修改类型是(如您所料)从可变长度数组派生的类型(例如,通过添加数组维度或 cv 限定符):

6.7.6 声明符

3 - [...] 如果在完整声明符的嵌套声明符序列中,有一个声明符指定了可变长度数组类型,则完整声明符指定的类型被称为可变修改。此外,通过声明符类型派生自可变修改类型的任何类型本身都是可变修改的。

于 2013-01-31T16:20:08.077 回答
-2

C89 标准的作者认识到许多实现实现了在其他实现上可能不切实际的有用特性,并认为这是一件好事。该标准旨在作为实施的最低要求;它从来没有打算阻止实现提供除此之外的功能。

该标准要求,如果符合要求的实现允许在块范围内定义的结构内声明可变长度数组,则它必须将此类行为记录为扩展,或者在代码包含此类声明时发出诊断。由于在发出这样的诊断后,实现可以随意处理代码,无论它是否记录了扩展,因此对记录扩展的要求只能有意义地应用于不生成诊断的扩展。这反过来又表明这样的事情必须是允许的。

该标准确实要求扩展不会对任何严格符合程序的行为产生不利影响,但是由于没有这样的程序可以在结构中包含 VLA 声明,因此这里的要求不是问题。

于 2017-03-06T18:04:23.693 回答