Min*_*s97 10 c gcc c99 variable-length-array
我对C99的可变修改型系统感兴趣.这个问题的灵感来自于这个问题.
检查这个问题的代码,我发现了一些有趣的东西.考虑以下代码:
int myFunc(int, int, int, int[][100]);
int myFunc(int a, int b, int c, int d[][200]) {
/* Some code here... */
}
Run Code Online (Sandbox Code Playgroud)
这显然不会(也不会)编译.但是,这段代码:
int myFunc(int, int, int, int[][100]);
int myFunc(int a, int b, int c, int d[][c]) {
/* Some code here... */
}
Run Code Online (Sandbox Code Playgroud)
编译甚至没有警告(在gcc上).
这似乎意味着可变修改的阵列类型与任何非可变修改的阵列类型兼容!
但那还不是全部.您期望一种可变修改类型至少可以使用哪个变量来设置其大小.但它似乎没有这样做!
int myFunc(int, int b, int, int[][b]);
int myFunc(int a, int b, int c, int d[][c]) {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
也编译没有任何错误.
所以,我的问题是:这是正确的标准化行为吗?
此外,如果一个可变修改的数组类型真的与任何具有相同维度的数组兼容,那么这不会意味着令人讨厌的安全问题吗?例如,请考虑以下代码:
int myFunc(int a, int b, int c, int d[][c]) {
printf("%d\n", sizeof(*d) / sizeof((*d)[0]));
return 0;
}
int main(){
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
myFunc(0, 0, 100, &arr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译并输出100,没有错误或警告,什么都没有.正如我所看到的那样,这意味着即使您严格检查阵列的大小sizeof
,也不会进行单一演员甚至打开所有警告,也可以轻松进行越界数组写入!或者我错过了什么?
C99,第6.7.5.2节似乎给出了相关规则。尤其,
6号线:
为了使两个数组类型兼容,两者都应具有兼容的元素类型,并且如果两个大小说明符都存在,并且都是整数常量表达式,则两个大小说明符应具有相同的常量值。如果两个数组类型在要求它们兼容的上下文中使用,则如果两个大小说明符的计算结果不相等,则这是未定义的行为。
之前的一个现已删除的答案也引用了第 6 行。对该答案的评论认为,第二句话受第一句话末尾的条件约束,但这似乎不太可能是这样的解读。该部分的示例 3 可能会澄清(摘录):
int c[n][n][6][m];
int (*r)[n][n][n+1];
r=c; // compatible, but defined behavior only if
// n == 6 and m == n+1
Run Code Online (Sandbox Code Playgroud)
这似乎与问题中的示例相当:两种数组类型,一种具有恒定维度,另一种具有相应的可变维度,并且需要兼容。当运行时变量维度与编译时常量维度不同时,行为未定义(根据示例 3 中的注释和 6.7.5.2/6 的合理阅读)。无论如何,未定义的行为不是您所期望的吗?不然为什么要提出这个问题呢?
假设我们可以同意,当发生这种不匹配时,行为是未定义的,我观察到,编译器通常不需要识别未定义或可能未定义的行为,也不需要发出任何类型的诊断(如果它们确实识别了这种行为)。我希望在这种情况下,编译器能够对可能未定义的行为发出警告,但它必须成功编译代码,因为它在语法上是正确的并且满足所有适用的约束。请注意,能够对此类使用发出警告的编译器默认情况下可能不会这样做。