int main()是否需要在C ++上进行声明?

时间:2019-04-01 14:37:52

标签: c++ main forward-declaration function-declaration

在C ++上学习函数时,有人告诉我函数需要调用声明。例如:

#include <iostream>

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

int sum(int x, int y) {
  return x + y;
}

由于没有为函数sum声明,它将返回错误。

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这样的其他函数添加声明?

7 个答案:

答案 0 :(得分:61)

函数的定义也是函数的声明。

声明函数的目的是使编译器知道该函数。在不定义函数的情况下声明函数可以在不方便定义函数的地方使用该函数。例如:

  • 如果在源文件(A)中使用的函数不同于在(B)中定义的函数,则我们需要在A中声明它(通常通过A包含的标头,例如B.h )。
  • 如果两个或多个函数可以相互调用,则我们不能在所有其他函数之前定义所有这些函数-必须先定义其中一个。因此可以先提供声明,然后再提供定义。
  • 许多人倾向于将“更高级别”的例程放在源文件中,然后将其放在子例程中。由于那些“更高级别”的例程会调用各种子例程,因此必须更早声明这些子例程。

在C ++中,用户程序从不调用main,因此在定义之前它不需要声明。 (请注意,您可以根据需要提供一个。在这方面,main的声明没有什么特别的。)在C语言中,程序可以调用main。在这种情况下,确实需要在调用之前可见声明。

请注意,调用它的代码确实需要知道main。这是通常称为C ++运行时启动代码的特殊代码。当您使用适当的链接器选项链接C ++程序时,链接器会自动为您提供该代码。无论使用哪种语言编写代码,它都必须具有main声明才能正确调用。

答案 1 :(得分:40)

  

有人告诉我,函数需要调用声明。

的确。必须先声明一个函数,然后才能对其进行调用。

  

为什么我们不为main函数添加声明?

好吧,您没有调用main函数。实际上,您绝对不能完全调用main 1 ,因此永远不需要在任何内容前声明main

尽管从技术上讲,所有定义也是声明,所以您对main的定义也声明了main


脚注1:C ++标准说从程序内部调用main是未定义的行为。

如果C ++实现无法通过通常调用main的启动代码中的钩子使它运行得更早,则可以将特殊的一次运行启动代码放在main的顶部。实际上,某些真正的实现确实做到了这一点,例如调用一个快速数学函数,该函数会设置一些FPU标志,例如denormals-are-zero。

在假设的实现中,调用main可能会导致有趣的事情,例如重新运行所有静态变量的构造函数,重新初始化new / delete用来跟踪分配的数据结构,或其他程序的整体损坏。否则可能根本不会引起任何问题。未定义的行为并不意味着它在每个实现上都会失败。

答案 2 :(得分:34)

如果要调用该函数,则原型是必需的,但尚不可用,例如sum

您不得自己致电main,因此无需原型。编写原型甚至是个坏主意。

答案 3 :(得分:25)

否,编译器不需要main()的前向声明。

main()是C ++中的特殊功能。

有关main()的一些重要的事情要记住:

  1. 链接器在创建可执行程序时要求只有一个main()函数。
  2. 编译器期望main()函数具有以下两种形式之一:
int main () { /* body */ } 
int main (int argc, char *argv[]) { /* body */ } 

其中body是零个或多个语句

另一种可接受的形式是特定于实现的,并在调用函数时提供了环境变量的列表:

int main (int argc, char* argv[], char *envp[]) { /* body */ }

编码器必须使用以下可接受的形式之一提供main的“定义”,但是编码器不需要提供声明。编译器接受编码后的定义作为main()的声明。

  1. 如果未提供return语句,则编译器将提供return 0;作为函数体内的最后一条语句。

顺便说一句,有时对于C ++程序是否可以调用main()感到困惑。不建议这样做。 C ++ 17草案指出main()“不得在程序内使用”。换句话说,不能从程序内部调用。参见例如Working Draft Standard for C++ Programming Language, dated "2017-03-21", Paragraph 6.6.1.3, page 66。我意识到有些编译器(包括我的)支持此功能,但是下一版本的编译器可以修改或删除该行为,因为标准使用了“不得”一词。

答案 4 :(得分:10)

从程序内部调用main是非法的。这意味着唯一需要调用的是运行时,编译器/链接器可以进行设置。这意味着main不需要原型。

答案 5 :(得分:7)

函数的定义也隐式声明了它。如果需要在定义函数之前先引用它,则需要在使用它之前声明它。

因此,编写以下内容也是有效的:

int sum(int x, int y) {
  return x + y;
}

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

如果在一个文件中使用声明使编译器在定义函数之前就知道该函数,则必须在链接时知道其定义:

main.cpp

int sum(int x, int y);

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

sum.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)只是表示代码的入口点。

答案 6 :(得分:5)

不。您还是不能叫它。

您只需要在定义函数之前就对其进行正向声明。对于其他文件中定义的函数,您需要外部声明(看起来像故意的前向声明)。

但是您无法在C ++中调用main,因此您不需要一个。这是因为允许C ++编译器修改main来进行全局初始化。

[我看了看crt0.c,它确实有main的声明,但是这里和那里都没有。]