我能够使用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。
答案 0 :(得分:3)
gcc
目前使用-std=gnu89
进行编译(不确定是否为5.x,但之前的版本确实如此)。在C89(GNU89几乎是C89-superset)中,如果在没有声明可见的情况下调用函数,则假定它被声明为
extern int f();
具有外部链接的函数,返回int
,并接受未指定(但固定)的默认提升参数。
这被许多人认为是一个设计错误,在C89中被标记为过时,并最终在C99中删除。默认情况下,Gcc会对隐式函数声明发出警告。
如果使用错误类型或数量的参数调用函数,则行为未定义,仅当prototype-declaration在调用范围内时才需要诊断。该标准对实现的作用没有要求,链接器将被允许失败(但通常不会)。
使用包含原型的头文件来获取警告。
通常,C编译器将源文件分别编译为目标文件,其中存储函数的符号时没有任何关于其参数类型的信息,因此链接器无法检查它们。
答案 1 :(得分:1)
编辑:
我想我最初误会了:
&#34;当没有函数声明时,gcc不知道在编译时阶段会发生什么,只要它在链接阶段找到函数,一切都会起作用。这个&#39;错误&#39;必须在编译阶段被捕获,因为从技术上讲,它在链接阶段根本不是错误。&#34;
老答案:
这是一项功能而非错误。调用函数时,参数会被压入堆栈。如果你不使用它们,一般没什么大不了的。
您甚至可以计划拥有未知数量的参数。以下是用于记录的自定义printf样式函数的简单示例:
void Debug_Message(uint32_t level, const char *format, ...)
{
char buffer[256];
//check level and do stuff
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
//buffer now contains data as if we did an sprintf to it
}
这就像printf一样被调用,可能是:
Debug_Message(1, "%d%d%d", 1, 2, 3);
可能是:
Debug_Message(1, "%d", 1);