【发布时间】:2014-12-05 20:18:02
【问题描述】:
我可以使用 gcc 4.4.7 编译和运行以下代码。
文件:m.c
#include <stdio.h>
int main()
{
printf("%d\n", f(1, 2, 3));
}
文件:f.c
int f(int a, int b)
{
return a + b;
}
输出:
$ gcc m.c f.c && ./a.out
$ 3
在同一文件中定义函数f() 时,编译器会按预期抛出错误。我的猜测是编译器无法检测到编译单元之间函数的错误使用。但是链接器不应该能够检测到它吗?标准是否指定了预期的行为?
请注意,这与声明没有任何参数的函数不同,即使在单个文件中也可以。 (Why does gcc allow arguments to be passed to a function defined to be with no arguments?)。
我正在使用 gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11) 和 GNU ld 版本 2.20.51.0.2-5.42.el6 20100205。
【问题讨论】:
-
C 没有进行类型检查或类型安全:-(
-
为了与 1989 年之前编写的 C 程序兼容。但是,上面的代码调用了未定义的行为。 “如果表示被调用函数的表达式的类型不包含原型......如果参数的数量不等于参数的数量,则行为未定义。”
-
为避免此问题,请在
f.c和任何调用f的源文件中添加带有原型int f(int a, int b);的标头f.h和#include该标头。并使用参数调用 gcc,使其警告对未声明函数的调用,-std=cXX用于不需要 GNU 扩展的代码,或-std=gnuXX用于需要 GNU 扩展的代码(其中XX是99或11)。 -
在 C(和其他几种语言)中,传递的参数被压入堆栈,最后一个参数首先由调用函数,然后是 pc,然后是来自被调用函数的自动变量。因此,从被调用函数的角度来看,它在堆栈上看到的并没有什么区别。这种将最后一个参数首先压入堆栈的方法使 va-arg 类型的函数(如 printf)能够正常工作。
-
额外的参数在编译时没有被捕获,因为代码缺少每个函数的原型(应该总是被使用,并且 gcc 的某些参数将强制使用)原型。
标签: c gcc compiler-errors linker