CERT安全编码标准包含一个项目(API05-C),它鼓励使用一致性数组参数,这是我在很多代码中实现的建议(隐藏在宏后面,用于不支持它们的编译器)。
对于那些不知道的人来说,一个符合的数组参数是这样的:
void foo(int length, char data[length]);API05-C提供了更多信息。
很多编译器不喜欢变长数组(理由很充分)。C11将它们从必需的(就像在C99中那样)降为可选的(编译器应该定义__STDC_NO_VLA__,如果它们没有实现)。MSVC不支持他们。IAR将它们隐藏在交换机(--vla)后面。GCC和clang会警告你,如果你问(用-Wvla,或者-Werror=vla,如果你想出错的话)。
一致性数组参数不会遇到与“正常”可变长度数组相同的问题;它们不会导致变量堆栈的使用。它们只是告诉编译器,现有的数组(可以在堆栈或堆上)有多大。
我的问题是,我所知道的每个编译器都将一致的数组参数作为VLA对待。对于像MSVC这样的编译器来说,这不是什么大问题,因为我可以将宏定义为零,但是对于GCC和clang这样的编译器,我想使用一致的数组参数,但不想触发-Wvla诊断。
根据API05-C (重点后加):
因此,充当函数参数的数组声明可能具有一个变量或表达式的索引。数组参数被降级为指针,因此不是可变长度数组(VLA)。开发人员可以使用一致性数组参数来指示数组的预期界限。编译器可以使用此信息,也可以忽略此信息。但是,这样的声明对于开发人员很有用,因为它们用于记录数组大小和指针之间的关系。静态分析工具也可以使用这些信息来诊断潜在的缺陷。
我非常希望这是真的,但我似乎找不到C99或C11标准的相关部分。
因此,严格按照C99/C11标准,是否有一致的数组参数VLA?或者,换句话说,传递数组作为参数是否真的将数组降级为指针?
显然,请引用规范的相关部分。
发布于 2018-04-22 05:28:16
声明为数组类型的所有参数都转换为指针类型。弗拉斯也不例外。
N1256 (C99+TC1+TC2+TC3):
6.7.5.3函数声明器(包括原型) 7将参数声明为“类型数组”应调整为“限定指针到类型”,其中类型限定符(如果有的话)是在数组类型派生的
[和]中指定的。如果关键字static也出现在数组类型派生的[和]中,那么对于函数的每个调用,对应的实际参数的值应该提供对数组的第一个元素的访问,至少与大小表达式指定的元素相同。
声明为void f(int a[10]);的函数接受任何int *。声明为void f(int length, int array[length]);的函数接受int和int *。
然而,你写的是:
我的问题是,我所知道的每个编译器都将一致的数组参数作为VLA对待。对于像MSVC这样的编译器来说,这不是什么大问题,因为我可以将宏定义为零,但是对于GCC和clang这样的编译器,我想使用一致的数组参数,但不想触发
-Wvla诊断。
嗯,这很棘手。在将其转换为指针之前,它是一个VLA,-Wvla的目的是警告不支持VLA的编译器上可能无法编译的代码。正如您所看到的,MSVC不喜欢代码。
一致性数组参数不会遇到与“正常”可变长度数组相同的问题;它们不会导致变量堆栈的使用。它们只是告诉编译器,现有的数组(可以在堆栈或堆上)有多大。
不,他们不会那样做的。给定void f(int a[10]);,使用空指针调用f是完全有效的,具有长度为1的数组的指针,等等。编译器必须支持这一点。它们只是对人类读者的一种暗示。这同样适用于转换后的VLA。
发布于 2018-04-22 06:08:04
它们不是VLA,而是指针。如果将该规则扩展到多个维度,则可以获得修改后的类型VM,而不是VLA。
如果要指示指针不应为0,则存在static,如
void Toto(size_t n, double vec [static n]);这表明vec必须至少有n元素,特别是不能为null。
https://stackoverflow.com/questions/49962479
复制相似问题