C 的 main()函数的有效签名是什么?

C 语言中主函数的有效签名到底是什么? 我知道:

int main(int argc, char *argv[])

还有其他有效的方法吗?

53556 次浏览

C11标准明确提到了以下两点:

int main(void);
int main(int argc, char* argv[]);

不过,它确实在下面的脚注中提到了“或相当于”这个短语:

因此,int可以被定义为 inttypedef名称替换,或者 argv的类型可以写为 char ** argv,依此类推。

此外,它还提供了更多(实现定义的)可能性。

相关文本(5.1.2.2.1节,但这个特定方面与 C99不同)指出:

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

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

或者带有两个参数(这里称为 argcargv,不过可以使用任何名称,因为它们是声明它们的函数的本地名称) :

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

或等价物; 或以其他实现定义的方式。

如果声明了这些参数,则 main函数的参数应遵守以下约束:

  • argc的值应该是非负的。

  • argv[argc]应为空指针。

  • 如果 argc的值大于零,那么包括 argv[0]argv[argc-1]在内的数组成员应该包含指向字符串的指针,这些字符串在程序启动之前由主机环境提供实现定义的值。其目的是从宿主环境中的其他地方向程序启动前确定的程序信息提供。如果主机环境不能同时提供大小写字母的字符串,则实现应确保以小写字母接收字符串。

  • 如果 argc的值大于零,则 argv[0]指向的字符串表示程序名; 如果程序名在主机环境中不可用,则 argv[0][0]应为空字符。如果 argc的值大于1,则 argv[1]通过 argv[argc-1]指向的字符串表示程序参数。

  • 参数 argcargv以及由 argv数组指向的字符串应该可以被程序修改,并且在程序启动和程序终止之间保留它们最后存储的值。

请注意,这是针对一个宿主环境的,就是您通常在 C 程序中看到的那种环境。独立的环境(例如嵌入式系统)受到的约束要少得多,正如同样标准的 5.1.2.1所述:

在一个独立的环境中(在这种环境中,C 程序的执行可能发生在没有操作系统任何好处的情况下) ,程序启动时调用的函数的名称和类型是实现定义的。独立程序可用的任何图书馆设施,除了第4条所要求的最小集合外,都是实现定义的。

int main(void)

在某些操作系统(例如 Windows)下,这也是有效的:

int main(int argc, char **argv, char **envp)

其中 envp提供了一个环境,否则通过 getenv()访问

POSIX 支持 execve(),而 execve()又支持

int main(int argc, char *argv[], char *envp[])

添加的参数是环境,即 NAME = VALUE 格式的字符串数组。

Http://en.wikipedia.org/wiki/main_function_(programming)#c_and_c.2b.2b

除了通常的 int main(int argc, char *argv[])和 POSIX int main(int argc, char **argv, char **envp)之外,在 Mac OS X 上也支持

int main(int argc, char* argv[], char* envp[], char* apple[]);

当然是 Mac 专用的。

窗户上有

int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);

作为 Unicode (实际上是宽字符)变体。当然也有 WinMain

标准 C

对于一个托管环境(这是正常的) ,C99标准说:

5.1.2.2.1程序启动

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

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

或者带有两个参数(这里称为 argcargv,不过可以使用任何名称,因为它们是声明它们的函数的本地名称) :

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

或等价物; 9)或以某种其他实现定义的方式。

9) 因此,int可以被定义为 int的 typedef 名称替换,或者 argv的类型可以写为 char **argv,依此类推。

C11和 C18标准与 C99标准基本相同。

标准 C + +

C + + 98标准规定:

3.6.1 Main 函数[ basic.start.Main ]

一个程序应该包含一个名为 main 的全局函数,它是程序的指定开始

2实现不应预先定义主函数。此函数不应超载 返回类型为 int 类型,但其类型是实现定义的。 所有实施方案 容许下列两种主要定义同时存在:

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

还有

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

C + + 标准明确表示“ It [ The main function ]应该具有 int类型的返回类型,但除此之外它的类型是实现定义的”,并且需要与 C 标准相同的两个签名。因此,“ void main ()”直接不被 C + + 标准所允许,尽管它无法阻止不符合标准的实现允许替代品(也无法阻止符合标准的实现允许替代品作为标准的扩展)。

C + + 03、 C + + 11、 C + + 14和 C + + 17标准基本上与 C + + 98相同。

共同延伸

传统上,Unix 系统支持第三种变体:

int main(int argc, char **argv, char **envp) { ... }

第三个参数是指向字符串的以空结尾的指针列表,每个指针都是一个环境变量,它有一个名称、一个等于号和一个值(可能为空)。如果你不使用这个,你仍然可以通过“ extern char **environ;”获得环境。这个变量(仍然)没有在任何 POSIX 头中声明(尽管这个问题的答案是以前的版本)。

C 标准认为这是一种常见的扩展,见附件 J:

5.1环境论据

1在宿主环境中,main 函数接收第三个参数 char *envp[], 指向指向 char的以空结尾的指针数组,每个指针指向一个字符串 提供有关执行程序的环境的信息(5.1.2.2.1)。

微软 C

Microsoft VS 2010编译器很有趣,网站上说:

Main 的声明语法为

 int main();

或者,可以选择,

int main(int argc, char *argv[], char *envp[]);

或者,可以将 mainwmain函数声明为返回 void(没有返回值)。如果将 mainwmain声明为返回 void,则不能使用 return 语句向父进程或操作系统返回退出代码。若要在 mainwmain声明为 void时返回退出代码,必须使用 exit函数。

我不清楚当一个具有 void main()的程序退出时会发生什么(退出代码返回给父代码或 o/s)ーー而且 MS 网站也是静默的。

有趣的是,MS 并没有规定 C 和 C + + 标准所要求的 main()的双参数版本。它只规定了一个三参数形式,其中第三个参数是 char **envp,一个指向环境变量列表的指针。

Microsoft 页面还列出了其他一些选项ーー使用宽字符字符串的 wmain()等等。

MicrosoftVS2005版本的 这一页没有列出 void main()作为替代。从 Microsoft VS 2008开始的 版本可以。

int main()int main(void)是一样的吗?

有关详细分析,请参阅我对 main()在 C 和 C + + 中应该返回什么的回答的结尾。(好像我曾经认为这个问题指的是 C + + ,尽管它并没有也从来没有。在 C + + 中,int main()int main(void)没有区别,int main()是习语 C + + 。)

在 C 语言中,这两种表示法之间存在差异,但是只有在深奥的情况下才会注意到这一点。具体来说,如果您从自己的代码调用 main()函数,那么这两者之间是有区别的,您可以在 C 语言中调用 main()函数,但是在 C + + 中不允许这样做。

int main()表示法并不提供 main()的原型,但是只有递归地调用它时才有意义。对于 int main(),你可以稍后(在同一个函数中,或者在另一个函数中)编写 int rc = main("absolute", "twaddle", 2):,正式地说,编译器不应该抱怨到拒绝编译代码的程度,尽管它可能会合法地抱怨(警告你)(并且在 GCC 中使用 -Werror会将这个警告转换成一个错误)。如果使用 int main(void),随后对 main()的调用应该会生成一个错误ーー您说函数不接受参数,但试图提供三个参数。当然,在声明或定义 main()之前,您不能合法地调用它(除非您仍然使用 C90语义)ーー而且实现没有声明 main()的原型。注意: C11标准在不同的示例中说明了 int main()int main(void)ーー它们在 C 中都是有效的,尽管它们之间存在细微的差别。