符合数组参数是否为VLA?

时间:2018-04-22 04:22:59

标签: c language-lawyer c99 c11 variable-length-array

CERT's Secure Coding Standard包含一个项目(API05-C),它鼓励使用一致的数组参数,这是我在很多代码中实现的建议(隐藏在a macro后面不支持它们的编译器。)

对于那些不知道的人,一致的数组参数类似于:

void foo(int length, char data[length]);

API05-C提供了更多信息。

许多编译器不喜欢可变长度数组(有充分理由)。 C11将它们从必需(因为它们在C99中)降级为可选(如果它们没有实现,编译器应该定义__STDC_NO_VLA__)。 MSVC扁平化不支持它们。 IAR将它们隐藏在一个开关(--vla)后面。如果您(-Wvla-Werror=vla询问错误,GCC和clang会向您发出警告)。

符合数组参数不会遇到与“普通”可变长度数组相同的问题;它们不会导致堆栈使用变量。他们只是告诉编译器现有数组(可能在堆栈或堆上)有多大。

我的问题是我所知道的每个编译器都将符合数组的参数视为VLA。这对于像MSVC这样的编译器来说并不是什么大问题,因为我可以将我的宏定义为空,但对于像GCC和clang这样的编译器我想使用一致的数组参数但不想触发-Wvla诊断。

根据API05-C(重点补充):

  

因此,用作函数参数的数组声明可以具有作为变量或表达式的索引。 数组参数降级为指针,因此不是可变长度数组(VLA)。开发人员可以使用符合数组参数来指示数组的预期范围。编译器可以使用此信息,也可以忽略它。但是,这样的声明对开发人员很有用,因为它们用于记录数组大小和指针之间的关系。静态分析工具也可以使用此信息来诊断潜在缺陷。

我迫切希望这是真的,但我似乎无法找到C99C11标准的相关部分。

那么,严格依据C99 / C11标准,是符合数组参数的VLA?或者,换句话说,将数组作为参数传递真的将它降级为指针吗?

显然,请引用规范的相关部分。

2 个答案:

答案 0 :(得分:1)

声明为数组类型的所有参数都将转换为指针类型。 VLA也不例外。

N1256(C99 + TC1 + TC2 + TC3):

  

6.7.5.3函数声明符(包括原型)

     

7参数声明为“数组类型”应调整为“限定指向类型的指针”,其中类型限定符(如果有)是[]中指定的类型限定符数组类型推导。如果关键字static也出现在数组类型派生的[]内,那么对于每次调用该函数,相应实际参数的值应提供对第一个的访问权限。数组的元素,其元素至少与size表达式指定的元素一样多。

声明为void f(int a[10]);的函数需要int *。声明为void f(int length, int array[length]);的函数需要intint *

但是,你写道:

  

我的问题是我所知道的每个编译器都将符合数组的参数视为VLA。这对于像MSVC这样的编译器来说并不是什么大问题,因为我可以将我的宏定义为空,但对于像GCC和clang这样的编译器我想使用一致的数组参数但不想触发-Wvla诊断。

嗯,这很棘手。它在转换为指针之前一个VLA,而-Wvla的点是警告无法在不支持VLA的编译器上编译的代码。如您所见,MSVC不喜欢该代码。

  

符合数组参数不会遇到与“普通”可变长度数组相同的问题;它们不会导致堆栈使用变量。他们只是告诉编译器现有数组(可能在堆栈或堆上)有多大。

不,他们不这样做。给定void f(int a[10]);,使用空指针调用f,使用指向长度为1的数组的指针等完全有效。编译器必须支持它。它们只是人类读者的暗示。这同样适用于转换的VLA。

答案 1 :(得分:0)

它们不是VLA,而只是指针。如果将该规则扩展到多个维度,则会获得可变修改类型VM,但仍不是VLA。

如果要指示指针不应为0,则

中有static
void Toto(size_t n, double vec [static n]);

表示vec必须至少有n个元素,特别是不能为空。