我知道在C编译器中,main()
函数是由_start()
函数调用的,其代码大致如下:
exit(main()); // return value of main is returned
当main()
的返回类型为void
、float
或其他类型时,_start()
如何工作?
如果 main
没有返回 int
,那么你的程序就是不合法的,行为是未定义的。任何事情都可能发生。你的程序可能会崩溃,或者它可能像什么都没有发生一样运行。
假设 main
返回了除 int
以外的其他类型,并且你的编译器和链接器允许生成该程序。但是调用者并不知道这一点。如果调用者期望返回的 int
值存储在 EAX(Intel)寄存器中,则它将读取该值以确定 main
的返回值。如果你有缺陷的 main
在那里存储了一个 float
值,那么它将被解释为一个 int
。 (这并不意味着它会被截断。它意味着组成浮点值布局的位将代替组成 int
的位。)如果你有缺陷的 main
返回了 void
,那么它没有在预期的寄存器中存储任何内容,因此调用者将得到先前在该寄存器中存储的任何值。
如果你的 main
返回某个类型,它期望将其存储在调用者没有为其保留内存的某个位置(例如一个大型结构体),那么它将覆盖其他东西,可能是程序干净关闭所必需的重要内容,导致你的程序崩溃。
cdecl
在ST0
中返回浮点数。新的SIMD寄存器仅在x64中使用,其中XMM0
包含FP返回值。 - MSaltersmain
可以返回除int
以外的其他类型--但是在托管型实现中很少有好的理由这样做。 - Keith ThompsonC标准从未提到过这个_start
函数;我认为C++也没有。
在1999年之前的ISO标准中,如果执行到main()
的结尾而没有执行return
语句,或者执行了一个没有指定返回值的return
语句,则“返回给主机环境的终止状态是未定义的”。实际上,我见过这样的程序返回1(失败)或一些任意的内存值,例如最后调用的函数的结果。
1999年的ISO C标准改变了这个规则:“到达终止main函数的}会返回值0”。这符合C++自至少1998年第一个ISO C++标准以来的规则。
(作为一种风格,即使不是强制要求,我喜欢在main
的末尾明确使用return 0;
。这与除main
外的其他int
函数一致,并且可以更好地移植到C99之前的编译器中。)
所有这些都假设main
的返回类型是int
。这是C标准特别支持的唯一类型(int main(void)
或int main(int argc, char *argv[])
或等效形式),但(托管)实现可以支持其他实现定义的定义。C90标准没有明确涵盖这种情况,但C99说:“如果返回类型与int不兼容,则返回给主机环境的终止状态是未指定的。”
C++标准有些不同。对于托管实现,main
必须被定义为返回int
。参数是实现定义的,但C的两个标准形式都必须得到支持。
对于用C或C++进行托管实现,我不知道有什么好的理由来定义 main
的返回类型除了int
。只需使用这两个标准定义之一,问题就不会出现。
对于“自由实现”,“程序启动时调用的函数的名称和类型为实现定义”。因此入口点可能合法地返回void
或其他内容,并且它甚至可能不被称为main
。请注意,“自由实现”是指“在其中可以执行C程序而无需任何操作系统支持”的典型嵌入式系统。
该函数将返回一个实现定义的值。例如,在C++中,main
隐式地返回0
。在void
main的情况下,则会由_start
简单地返回此值。但是,几乎没有任何实现允许任意的返回类型-退出进程时都必须使用整数值,这已经被嵌入到操作系统中了。
在C++中,如果从main()
函数中返回除了int
以外的任何类型,那么将会出现编译错误:
error: ‘::main’ must return ‘int’
int
的浮点数:例如,2.1F将被重新解释为224。warning: return type of ‘main’ is not ‘int’
。 - Sergey Kalinichenkomain
的返回类型不是int
,那么返回值就是实现定义的。简而言之,实现允许main
的返回类型与int
不同,但已知的实现都只支持int
类型。理想情况下,您需要参考平台和编译器的文档,以查看它定义的确切行为,因为标准允许其具有灵活性。int
返回类型,但除此之外,只要实现允许没有参数和argc
/argv
(即返回类型为int
,但main
函数的类型是实现定义的),则可以采用任何参数。我在等待咖啡沉淀,所以可能我说的不清楚... - dreamlax假设我们正在使用Visual Studio 2012。
对于C++程序,Visual Studio允许指定void
作为返回类型,尽管这在C++标准中是被禁止的。根据标准,在托管实现中,main()
必须返回一个int
。
对于C程序,main()
可以返回任何返回类型,但返回除int
以外的其他内容会导致未指定的行为。例如,在Visual Studio 2012下,从double main()
返回0.0
会导致在调试器中运行程序时返回值为0xcccccccc
(请参见在Visual Studio C++中,内存分配表示是什么?)。
int
是唯一允许的返回类型(对于托管实现)。 - Daniel Fischer
crt1.o
,它包含了你的_start()
,是直接用汇编语言编写的,因此它没有类型系统。无论最终在预期的内存位置(或寄存器)中出现什么,都将被用作您的返回值... - Kerrek SB