C语言中的main()函数

29

我以自学的方式学习C编程已经有几周了,有一些关于main()函数的问题。

  1. 所有函数都必须在其函数原型中声明,稍后在定义中使用。为什么我们不需要先在原型中声明main()函数?

  2. 为什么我们必须使用int main()而不是void main()

  3. main()函数中的return 0具体是做什么的?例如,如果我用return 1;结束main()函数,会发生什么?


9
main()甚至拥有自己的Wikipedia页面 - huysentruitw
7
错误 - 原型不是“必须”的。 - aragaer
2
@user2718426 注意,在这里,我们喜欢每次只提出一个问题。所以你的帖子听起来像是三个问题。虽然你会发现有很多关于第二个问题的文章,比如https://dev59.com/JWox5IYBdhLWcg3wNRtj。 - Prashant Kumar
在Unix系统上,您可以使用 $? 获取程序返回的值(在Windows上必须使用其他方法)。示例命令:./myprog && echo $? - Michael M.
@Michael:在Windows上使用cmd.exe,如果我没记错的话应该是%errorlevel%。 - Matteo Italia
显示剩余3条评论
9个回答

24
  1. 在函数被调用之前只需要声明该函数即可,定义本身也是一种声明,所以不需要先声明原型。 (一些编译器和其他工具可能会在没有先前原型的情况下定义函数并发出警告。这旨在作为一个有帮助的指南,而不是C语言规则的要求。)
  2. 因为C标准是这样规定的。操作系统将返回值传递给调用程序(通常是shell)。一些编译器将接受void main,但这是一种非标准扩展(它通常表示“始终向操作系统返回零”)。
  3. 按照惯例,非零的返回值表示发生了错误。Shell脚本和其他程序可以使用此返回值来确定您的程序是否成功终止。

C标准(至少从1999年到2018年的版本)中没有规定main函数不能从任何其他函数调用。第5.1.2.2.3条款甚至包括对“对main函数的初始调用”的引用,因此承认了后续调用的可能性。如果由于某种原因不能从任何其他函数调用任何函数(包括main函数),也没有规定它不能被声明。 - Eric Postpischil
可能C标准中的语句“实现对此函数[main]没有原型声明”会引起一些混淆,但它只是意味着C实现不提供声明。也就是说,它没有内置于编译器或任何标准头文件中。这并不意味着程序不能为main声明原型。 - Eric Postpischil

18

1) 所有函数必须在其函数原型中先声明,然后在其定义中再声明。为什么我们不必先在原型中声明main()函数?

不准确。简单的例子:

void foo(){}  //definition

int main()
{
    foo();
    return 0;
}

只有当调用一个函数但是其定义还没有被看到时,需要进行声明。由于main是程序的启动点,所以永远不会发生这种情况。


2) 为什么我们必须使用 int main() 而不是 void main()

因为标准是这样规定的。(更精确地说,在通常情况下,这适用于托管环境)

C99 5.1.2.2.1 程序启动

在程序启动时调用的函数名为 main。实现对该函数没有原型声明。它应该定义为返回类型为 int,无参数:

int main(void) { /* ... */ }

或者带有两个参数(这里称为argcargv,但任何名称都可以使用,因为它们是在声明它们的函数中局部的):

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

返回值表示程序的结果。通常,0表示成功,而其他值则表示不同类型的失败。


3
你不能自由选择main函数的返回类型,因为你没有编写调用main函数的代码。调用main函数的代码早在你学习C语言之前就已经存在了。这些代码是由提供C运行时启动代码的人员编写的,通常会自动链接到你的可执行文件中,而你并不知道。这些代码通常存储在一个名为crt0.o的文件中(由crt0.c或者汇编器生成的crt0.s),它期望使用一个返回值来表示成功(0)或失败(非零),以及可能包含其他信息,例如代码是否因信号终止,如果是,是哪个信号。这些都是Unix历史的一部分,我就不在这里重复了 :-)

1

1) 不一定;定义也可以作为声明。其次,对于main只有少数有效的签名,除非你写IOCCC的入口,否则通常不会在代码中调用main

2) 简短回答:因为语言定义如此。较长回答:这是程序向主机环境指示成功或失败的方式。个别实现可自由支持附加的main签名,但必须记录这些附加签名。如果编译器文档未将void main()列为合法签名,则不应使用它。

3) 按照惯例(至少在最初使用C的*nix系统中),状态0表示成功,而非零状态表示……而不是成功。哪个值对应于哪个状态取决于实现。


0
当我们运行C程序时,计算机控制权转移到C程序的main()函数,从那里开始执行C程序。

0

1) 这是错误的,你只能创建函数的定义。

2) 我们可以知道main()函数是否正确终止。

3) 相同,只是在您的shell中将写入1而不是0。


0

函数不一定需要先声明原型。只有当我们需要在定义之前使用函数时才需要这样声明。

根据定义,main函数的类型为int。

从main函数返回的值的含义是传统的。通常接受的约定是0被视为成功,而非0则表示某种失败。


0
1. main()函数是由C库通过识别内置关键字'main'来隐式调用的。因此,我们不需要为main函数声明原型。
2. 这个我不确定,但我认为它取决于所使用的编辑器类型。在Turbo C中,void main()将被接受,而在dev-cpp中,main()应返回一个值。
3. return 0简单地以退出状态0退出程序,换句话说,返回值确定了主线程的退出状态。

0

简单来说,所有问题的本质都是传统和一致性。 工具链、操作系统等知道这个过程称为main(),必须首先从用户代码空间(程序)中调用...

现在具体来说: 1)因为符合性,您不需要声明,因为工具链和操作系统已经知道了main。还有其他符合性函数,如exit()。

2)当主函数有返回时,操作系统可以从中获取结果。通常非零表示错误。因此,当您使用脚本或其他程序调用您的程序(例如main()函数)时,您可以检查它是否成功。

3)返回非零值表示错误。但实际上,您可以根据自己的意愿解释该值。但正如我所说,操作系统可以得到结果。

额外信息: main() 实际上不是你编写的程序启动时将被调用的第一个函数。实际上,操作系统和工具链会在 main 函数之前进行其他调用,以设置环境、进行初始化或执行其他操作。但是,在编写代码时,你并不直接了解这些内容,也无需考虑这些问题。在嵌入式系统中,通常会调用一些非常低级别的函数来设置 CPU 主时钟、中断、堆栈等。像 IAR 这样的一些工具链实际上可以让你在调用 main 函数之前执行自己的代码。
希望这有所帮助 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接