Nic*_*gny 0 c x86 gcc arm clang
摆弄C的旧奇怪兼容行为时,我最终得到了这段代码:
#include <stdio.h>
int f();
int m() {
return f();
}
int f(int a) {
return a;
}
int main() {
f(2);
printf("%i\n", m());
}
Run Code Online (Sandbox Code Playgroud)
我确定f()in 的调用m()是未定义的行为,因为f()应该只使用一个参数,但是:
-Wextra,-Weverything否则GCC 9.1和clang 8.0.1均不显示任何警告(也不显示in 或其他内容)-O3。然后输出为2,不带-O30,带0。在Windows上,MSVC不会输出任何错误,程序只会输出随机数。-O3仍输出0,但正常编译会导致GCC为2,而...则为66688。当出现错误消息时,几乎是您所期望的:(非常有趣,因为a在打印行中没有出现)
foo.c: In function ‘m’:
foo.c:4:9: warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
return f();
^~~
foo.c: In function ‘main’:
foo.c:11:2: warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
printf("%i\n", m());
Run Code Online (Sandbox Code Playgroud)
我的猜测是,这-O3会导致GCC内联这些呼叫,从而使他们了解发生了问题。并且将堆栈或寄存器中的残差用作调用的参数。但是如何仍然可以编译?这真的是(意外的)行为吗?
违反的特定规则是C 2018 6.5.2.2(函数调用)6:
如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升,并将具有该类型的参数
float提升为double。这些称为默认参数提升。如果参数数量不等于参数数量,则行为是不确定的。…
由于这不是约束,因此不需要编译器产生诊断信息-C标准完全没有定义行为,这意味着该标准完全没有要求。
由于该标准没有任何要求,因此忽略问题(或无法识别问题)和诊断问题都是允许的。