【发布时间】:2019-09-06 12:24:10
【问题描述】:
在摆弄 C 的旧的奇怪兼容性行为时,我最终得到了这段代码:
#include <stdio.h>
int f();
int m() {
return f();
}
int f(int a) {
return a;
}
int main() {
f(2);
printf("%i\n", m());
}
我确信在m() 中对f() 的调用是一种未定义的行为,因为f() 应该只接受一个参数,但是:
- 在 x86 上,GCC 9.1 和 clang 8.0.1 都不会显示任何警告(
-Wextra、-Weverything或其他任何内容),除非使用 GCC 和-O3。没有-O3的输出是 2,有它的输出是 0。在 Windows 上,MSVC 不会打印任何错误,并且程序只会输出随机数。 - 在 ARM (Raspberry Pi 3)、GCC 6.3.0 和 clang 3.8.1 上,我观察到相同的错误行为,选项
-O3仍然输出 0,但正常编译导致 2 与 GCC 和... 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());
我的猜测是-O3 引导 GCC 内联调用,从而使其了解发生了问题;并且堆栈或寄存器中的剩余部分被用作调用的参数。但它怎么还能编译呢?这真的是(未)预期的行为吗?
【问题讨论】:
-
你试过
-Wstrict-prototypes吗?无原型声明是 C 语言的过时错误功能,永远不应该使用。尝试对行为进行推理确实没有意义,因为它不适用于任何正确编写的真实世界代码库。 -
这确实有效,并且对我大喊大叫,因为我已经声明了没有原型的所有函数......谢谢!
-
考虑到 C89 引入的原型,'-Wstrict-prototypes' 不是默认的 30 年后有点遗憾。
-
关于“函数声明和定义中空括号是什么意思”的一般性讨论see this QA