在C++中,在声明函数之前调用函数是一个编译器错误.但在C语言中,它可能会编译.
#include<stdio.h>
int main()
{
foo(); // foo() is called before its declaration/definition
}
int foo()
{
printf("Hello");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试过并且知道它是正确的,但我无法理解它背后的原因.任何人都可以解释编译过程是如何实际发生的,并且两种语言都有所不同.
Iha*_*imi 12
代码" 编译 "为c程序的事实并不意味着你可以做到.编译器应该警告函数的隐式声明foo().
在这种特殊情况下,隐式声明会声明相同,foo()并且不会发生任何不良事件.
但假设有以下情况,请说明这一点
main.c中
/* Don't include any header, why would you include it if you don't
need prototypes? */
int main(void)
{
printf("%d\n", foo()); // Use "%d" because the compiler will
// implicitly declare `foo()` as
//
// int foo()
//
// Using the "correct" specifier, would
// invoke undefined behavior "too".
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在假设foo()在另一个编译单元1 foo.c中定义为
foo.c的
double foo()
{
return 3.5;
}
Run Code Online (Sandbox Code Playgroud)
它按预期工作吗?
您可以想象如果您在malloc()不使用stdio.h的情况下使用会发生什么,这与我上面尝试解释的情况非常相似.
因此,执行此操作将调用未定义的行为2,因此术语" Works "在这种情况下不适用于可理解的意义.
这可以编译的原因是因为在过去很久以前它被c标准所允许,即c89标准.
在C++标准从来不允许这样,所以你不能编译C++如果你调用一个没有原型("一个功能程序申报代码"),它被称为前.
现代c编译器警告这一点,因为可能容易发生未定义的行为,并且由于忘记添加原型或包含适当的头并不难,如果编译器可以对此进行警告而不是突然间有一个非常难以理解的bug.
1 它不能在同一个文件中编译,因为它将使用不同的返回类型定义,因为它已经被隐式声明
2 与事实出发double,并int有不同的类型,会有不确定的,因为这种行为.
在开发C时,函数名称就是您需要能够调用它的全部名称.函数参数的匹配参数完全是程序员的业务; 编译器并不关心你是否将三个浮点数传递给只需一个整数的东西.
然而,事实证明这很容易出错,因此后来C语言的迭代添加了函数原型作为(仍然是可选的)附加限制.在C++中,这些限制已经进一步加强:现在函数原型总是强制性的.
我们可以推测为什么,但部分原因是因为在C++中仅仅知道函数名称已经不够了.可以有多个具有相同名称但具有不同参数的函数,编译器必须确定要调用哪个函数.它还必须弄清楚如何调用(直接或虚拟?),甚至可能必须在模板函数的情况下生成代码.
鉴于我认为语言要求在调用函数时知道函数原型是有意义的.