即使我们在C程序中不包含stdio.h,为什么我们不会得到编译时错误?

时间:2008-09-16 02:19:57

标签: c compiler-construction

当我首先没有包含任何头文件时,编译器如何知道sleep函数的原型甚至printf函数?

此外,如果我指定sleep(1,1,"xyz")或任意数量的参数,编译器仍会编译它。 但奇怪的是gcc能够在链接时找到这个函数的定义,我不明白这是怎么回事,因为实际的sleep()函数只接受一个参数,但是我们的程序提到了三个参数

/********************************/
int main()
{
 short int i;
 for(i = 0; i<5; i++)
 {
    printf("%d",i);`print("code sample");`
    sleep(1);
 }
 return 0;
}

7 个答案:

答案 0 :(得分:10)

缺少更具体的原型,编译器会假设函数返回int并且接受你提供的任意数量的参数。

根据CPU体系结构,可以在寄存器中传递参数(例如,MIPS上的a0到a3),也可以像在原始x86调用约定中一样将它们推送到堆栈中。在任何一种情况下,传递额外的参数都是无害的。被调用的函数不会使用传入的寄存器,也不会引用堆栈上的额外参数,但不会发生任何不好的事情。

传入较少的参数更成问题。被调用的函数将使用发生在适当的寄存器或堆栈位置的任何垃圾,并且随后可能会出现hijink。

答案 1 :(得分:5)

在经典C中,您不需要原型来调用函数。编译器将推断该函数返回一个int并获取未知数量的参数。这可能适用于某些体系结构,但如果函数返回除int之外的其他内容(如结构)或者有任何参数转换,则它将失败。

在您的示例中,可以看到睡眠,编译器会假设像

这样的原型
int sleep();

请注意,参数列表为空。在C中,这与void不同。这实际上意味着“未知”。如果您正在编写K&amp; R C代码,则可以通过

等代码获取未知参数
int sleep(t)
int t;
{
   /* do something with t */
}

这一切都很危险,尤其是在一些嵌入式芯片上,其中为非原型函数传递参数的方式与原型不同。

注意:链接不需要原型。通常,链接器会自动链接到Linux上的glibc之类的C运行时库。您使用sleep和实现它的代码之间的关联发生在源代码处理很久之后的链接时间。

我建议您使用编译器的功能来要求原型以避免这样的问题。使用GCC,它是-Wstrict-prototypes命令行参数。在CodeWarrior工具中,它是C / C ++编译器面板中的“Require Prototypes”标志。

答案 2 :(得分:2)

C将猜测未知类型的int。所以,它可能认为睡眠有这个原型:

int sleep(int);

至于提供多个参数和链接......我不确定。这让我感到惊讶。如果真的有效,那么在运行时会发生什么?

答案 3 :(得分:2)

这与'K&amp; R C'和'ANSI C'。 在古老的K&amp; R C,如果未声明某些内容,则假定为int。 所以任何看起来像函数调用但没有声明为函数的东西 将自动获取'int'的返回值和依赖的参数类型 在电话会议上。

然而人们后来发现有时这可能非常糟糕。所以 几个编译器添加了警告。 C ++犯了这个错误。我认为gcc有一些 flag(-ansic或-pedantic?),这使得这个条件成为错误。

所以,简而言之,这是历史包袱。

答案 4 :(得分:2)

其他答案涵盖了可能的机制(所有猜测都没有指定编译器)。

您遇到的问题是您的编译器和链接器尚未设置为启用所有可能的错误和警告。对于任何新项目,(几乎)没有理由不这样做。 遗留项目更多的借口 - 但应努力尽可能多地启用

答案 5 :(得分:1)

取决于编译器,但是使用gcc(例如,因为那是你提到的那个),一些标准(包括C和POSIX)函数都内置了“编译器内在函数”。这意味着编译器附带的编译器库(在本例中为libgcc)包含该函数的实现。编译器将允许隐式声明(即,使用没有头的函数),链接器将在编译器库中找到实现,因为您可能将编译器用作链接器前端。

尝试使用'-c'标志编译对象(仅编译,无链接),然后使用链接器直接链接它们。你会发现你得到了你期望的链接器错误。

或者,gcc支持禁用内在函数的选项:-fno-builtin或粒度控制-fno-builtin-function。如果您正在构建自制内核或其他类型的金属应用程序,还有其他选项可能会有用。

答案 6 :(得分:1)

在非玩具示例中,其他文件可能包含您错过的文件。查看预处理器的输出是查看编译结果的好方法。