结构中间的可变长度数组——为什么这个C代码对gcc有效

时间:2022-09-30 03:13:16

There is some strange code using VLA (Variable Length Arrays) which is treated as Valid C (C99, C11) by gcc 4.6:

有一些使用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;
}

This code compiled without warnings:

此代码编译时没有警告:

$ 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

Same for -std=c1x:

相同化c1x:

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

But this does not work with Intel C Compiler or with Clang+LLVM:

但这与Intel 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.

So:

所以:

  1. Why is this considered valid by GCC?
  2. 为什么GCC认为这是有效的?
  3. If it is an extension of GCC, where is it described?
  4. 如果它是GCC的扩展,它在哪里描述?
  5. Is it valid in C99 and C11 ISO Standards?
  6. 它在C99和C11 ISO标准中有效吗?

3 个解决方案

#1


8  

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.

GCC不允许使用-std=c99 - pedanit错误进行编译。结构体内部的VLA显然是(缺乏文档的)非标准GNU C特性。看到这个。

#2


3  

The standard is pretty clear that VLAs are not allowed in a struct:

很明显,结构中不允许使用VLAs:

6.7.2.1 Structure and union specifiers

9 - A member of a structure or union may have any complete object type other than a variably modified type. [...]

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

Variably modified types are (as you might expect) those derived from a variable length array (e.g. by adding array dimensions or cv qualifiers):

可变修改类型是(正如您可能期望的那样)由可变长度数组派生的类型(例如通过添加数组维度或cv限定符):

6.7.6 Declarators

3 - [...] If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.

3 -[…[参考译文]如果在一个完整声明符的嵌套声明符序列中,有一个声明符指定一个可变长度数组类型,那么由完整声明符指定的类型就被称为可变修改的。此外,任何由声明类型派生自可变修改类型的类型都是可变修改的。

#3


-1  

The authors of the C89 Standard recognized that many implementations implemented useful features which might be impractical on other implementations, and recognized that as a good thing. The Standard was intended as a minimum set of requirements for implementations; it was never intended to discourage implementations from providing features beyond that.

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

The Standard requires that if a conforming implementation allows a variable-length array to be declared within a structure defined at block scope, it must either document such behavior as an extension or issue a diagnostic when code contains such a declaration. Since an implementation would be free to process the code however it likes after issuing such a diagnostic, whether or not it documents an extension, the requirement to document extensions can only be meaningfully applied to extensions which do not generate diagnostics. That in turn would suggest that such things must be allowable.

标准要求,如果一个合格的实现允许在一个在块范围内定义的结构中声明一个可变长度的数组,那么它必须在代码包含这样的声明时将这种行为记录为扩展或发出诊断。由于实现将可以*地处理代码,但是在发布了这样的诊断之后,不管它是否记录了扩展,对文档扩展的需求只能对不生成诊断的扩展有意义的应用。这反过来又表明,这些东西必须是允许的。

The Standard does require that extensions not adversely affect the behavior of any Strictly Conforming programs, but since no such program could contain a VLA declaration within a structure that requirement is not a problem here.

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

#1


8  

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.

GCC不允许使用-std=c99 - pedanit错误进行编译。结构体内部的VLA显然是(缺乏文档的)非标准GNU C特性。看到这个。

#2


3  

The standard is pretty clear that VLAs are not allowed in a struct:

很明显,结构中不允许使用VLAs:

6.7.2.1 Structure and union specifiers

9 - A member of a structure or union may have any complete object type other than a variably modified type. [...]

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

Variably modified types are (as you might expect) those derived from a variable length array (e.g. by adding array dimensions or cv qualifiers):

可变修改类型是(正如您可能期望的那样)由可变长度数组派生的类型(例如通过添加数组维度或cv限定符):

6.7.6 Declarators

3 - [...] If, in the nested sequence of declarators in a full declarator, there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified. Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.

3 -[…[参考译文]如果在一个完整声明符的嵌套声明符序列中,有一个声明符指定一个可变长度数组类型,那么由完整声明符指定的类型就被称为可变修改的。此外,任何由声明类型派生自可变修改类型的类型都是可变修改的。

#3


-1  

The authors of the C89 Standard recognized that many implementations implemented useful features which might be impractical on other implementations, and recognized that as a good thing. The Standard was intended as a minimum set of requirements for implementations; it was never intended to discourage implementations from providing features beyond that.

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

The Standard requires that if a conforming implementation allows a variable-length array to be declared within a structure defined at block scope, it must either document such behavior as an extension or issue a diagnostic when code contains such a declaration. Since an implementation would be free to process the code however it likes after issuing such a diagnostic, whether or not it documents an extension, the requirement to document extensions can only be meaningfully applied to extensions which do not generate diagnostics. That in turn would suggest that such things must be allowable.

标准要求,如果一个合格的实现允许在一个在块范围内定义的结构中声明一个可变长度的数组,那么它必须在代码包含这样的声明时将这种行为记录为扩展或发出诊断。由于实现将可以*地处理代码,但是在发布了这样的诊断之后,不管它是否记录了扩展,对文档扩展的需求只能对不生成诊断的扩展有意义的应用。这反过来又表明,这些东西必须是允许的。

The Standard does require that extensions not adversely affect the behavior of any Strictly Conforming programs, but since no such program could contain a VLA declaration within a structure that requirement is not a problem here.

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