我被教导函数需要调用声明。为了说明,以下示例会给我一个错误,因为函数sum
没有声明:
#include <iostream>
int main() {
std::cout << "The result is " << sum(1, 2);
return 0;
}
int sum(int x, int y) {
return x + y;
}
// main.cpp:4:36: error: use of undeclared identifier 'sum'
// std::cout << "The result is " << sum(1, 2);
// ^
// 1 error generated.
为了解决这个问题,我会添加声明:
#include <iostream>
int sum(int x, int y); // declaration
int main() {
std::cout << "The result is " << sum(1, 2);
return 0;
}
int sum(int x, int y) {
return x + y;
}
为什么main
函数不需要声明,而其他函数(如sum
)需要?
函数的定义也是函数的声明。
声明函数的目的是使编译器知道它。声明函数而不定义它允许在不方便定义它的地方使用函数。例如:
- 如果一个函数在源文件(A)中使用,而不是在(B)中定义的函数,我们需要在A中声明它(通常通过A包含的标头,例如
B.h
)。 - 如果两个或多个函数可以相互调用,那么我们不能在其他函数之前定义所有这些函数——其中一个必须是第一个。因此,可以先提供声明,然后再提供定义。
- 许多人更喜欢将"更高级别"的例程放在源文件的前面,把子例程放在后面。由于这些"更高级别"的例程调用各种子例程,因此必须更早地声明这些子例程。
在C++中,用户程序从不调用main
,所以它从不需要在定义之前声明。(请注意,如果您愿意,可以提供。在这方面,main
声明没有什么特别之处。在 C 语言中,程序可以调用main
。在这种情况下,它确实要求声明在调用之前可见。
请注意,调用它的代码确实需要知道main
。这是通常称为C++运行时启动代码的特殊代码。当您使用相应的链接器选项链接C++程序时,链接器会自动包含该代码。无论代码是用什么语言编写的,它都有正确调用它所需的任何main
声明。
我被教导函数需要调用声明。
事实上。必须先声明函数,然后才能调用该函数。
为什么我们不为
main
函数添加声明?
好吧,您没有调用main
函数。事实上,你绝对不能称main
为1,所以永远不需要在任何事情之前声明main
。
从技术上讲,所有定义也是声明,因此您对main
的定义也声明了main
。
脚注1:C++标准说从程序内部调用main
是未定义的行为。
这允许C++实现将特殊的运行一次启动代码放在 main 的顶部,如果他们无法让它更早地从通常调用main
的启动代码中的钩子运行。 一些实际实现确实这样做了,例如调用一个快速数学函数来设置一些 FPU 标志,如非正常为零。
在假设的实现中,调用 main 可能会导致有趣的事情,例如重新运行所有静态变量的构造函数,重新初始化new
/delete
使用的数据结构来跟踪分配,或者程序的其他完全破坏。 或者它可能根本不会引起任何问题。 未定义的行为并不意味着它必须在每次实现中都失败。
如果要调用函数,则需要原型,但它尚不可用,例如sum
。
您一定不能自己打电话给main
,因此无需原型。编写原型甚至是一个坏主意。
不,编译器不需要main()
的前向声明。
main()
是C++中的一项特殊功能。
关于main()要记住的一些重要事情是:
- 链接器要求在创建可执行程序时仅存在一个
main()
函数。 - 编译器需要以下两种形式之一的 main() 函数:
int main () { /* body */ }
int main (int argc, char *argv[]) { /* body */ }
其中body
为零个或多个语句
另一个可接受的形式是特定于实现的,并在调用函数时提供环境变量的列表:
int main (int argc, char* argv[], char *envp[]) { /* body */ }
编码人员必须使用这些可接受的形式之一提供 main 的"定义",但编码人员不需要提供声明。 编码的定义被编译器接受为 main() 的声明。
- 如果未提供 return 语句,编译器将提供一个
return 0;
作为函数体中的最后一个语句。
顺便说一句,有时对于C++程序是否可以调用main()存在混淆。 不建议这样做。 C++17草案规定main()"不得在程序中使用"。 换句话说,不能从程序内调用。 例如,参见C++编程语言标准工作草案,日期为"2017-03-21",第 6.6.1.3 段,第 66 页。 我意识到一些编译器支持这一点(包括我的编译器),但编译器的下一个版本可能会修改或删除该行为,因为标准使用术语"不应"。
从程序内部调用main
是非法的。 这意味着唯一要调用它的是运行时,编译器/链接器可以处理设置它。这意味着您不需要原型main
.
函数的定义也隐式声明了它。如果需要在定义函数之前引用函数,则需要在使用函数之前声明它。
所以写以下内容也是有效的:
int sum(int x, int y) {
return x + y;
}
int main() {
std::cout << "The result is " << sum(1, 2);
return 0;
}
如果在一个文件中使用声明使编译器在定义函数之前知道该函数,则必须在链接时知道其定义:
主.cpp
int sum(int x, int y);
int main() {
std::cout << "The result is " << sum(1, 2);
return 0;
}
总和.cpp
int sum(int x, int y) {
return x + y;
}
或者sum
可能起源于库,因此您甚至不需要自己编译它。
main
函数不会在代码中的任何位置使用/引用,因此无需在任何地方添加main
声明。
在main
函数之前和之后,C++ 库可能会执行一些初始化和清理步骤,并将调用main
函数。如果库的该部分表示为 c++ 代码,则它将包含int main()
声明,以便可以对其进行编译。该代码可能如下所示:
int main();
int __main() {
__startup_runtime();
main();
__cleanup_runtime();
}
但是你又遇到了同样的问题__main
所以在某些时候不再有c ++,某个函数(main
)只是代表代码的入口点。
不。反正你不能叫它。
您只需要在定义函数之前调用函数的前向声明。对于其他文件中定义的函数,您需要外部声明(看起来与特意的前向声明完全相同)。
但是你不能用C++打电话给main
,所以你不需要。这是因为允许C++编译器修改 main 以执行全局初始化。
[我查看了crt0.c,它确实有一个主要的声明,但这既不在这里也不在那里]。