//File a.c
void main()
{
test();
}
//File b.c
#include<stdio.h>
void test()
{
printf("Hi, I am test.");
}
我使用“gcc a.c b.c”编译此代码。然后我运行'a.out'并输出“你好我测试。”我的问题是在.c文件中没有test()的声明,为什么代码编译?
答案 0 :(得分:2)
默认情况下,C中的函数为extern
,这意味着即使没有a
,链接器也能够将文件b
中的函数连接到文件#include
。或extern
由程序员编写。
我的gcc使用此警告编译它:warning: implicit declaration of function...
意思是,通过查看test();
编译器猜测test
是什么,并继续。如果您将test
定义为失败的static
,那么static
将对抗默认extern
我认为您应该注意的一件事是implicit declaration
也使编译器猜测返回类型为test
,它会认为类型为{{1} }。这可能会导致问题。
答案 1 :(得分:1)
代码编译是因为C标准要求(至少在1999年之前)。在1999年的标准中删除了支持,尽管许多编译器仍然支持它 - 虽然它们可以被配置为在这种情况下警告(例如关于隐式声明)。
具体来说,出于向后兼容C89 / 90与预标准C的原因,代码调用函数的尝试隐式声明该函数返回int
,并接受变量参数列表。
当编译器通过a.c
工作时会发生这种情况链接时,它会起作用,因为该函数具有相同的名称。
如果调用函数的方式(返回值的使用和参数类型的数量)与函数的定义方式相匹配,这在实践中有效。如果没有匹配,则结果可能是未定义的行为。例如,如果函数使用4个参数定义并使用全部4,但调用者提供3,则行为未定义。同样,如果函数定义为返回double
,但调用者假定它返回int
。
实际上,最好在调用之前声明所有编译单元中的所有函数(例如,通过包含标题)。这允许编译器检查调用函数的方式是否与其声明相匹配。
另请注意,在所有C标准中,main()
都会返回int
,而不是void
。支持main()
返回void
是编译器扩展。