C中主要功能的有效签名究竟是什么?我知道:
int main(int argc, char *argv[])
还有其他有效的吗?
本回答(C11)时的现行标准明确提到了这两个:
int main(void);
int main(int argc, char* argv[]);
虽然它确实提到了“或等同”这一短语,但附有以下脚注:
因此,
int
可以被定义为typedef
的int
名称替换,或者argv
的类型可以被写为char ** argv
,依此类推。
此外,它还提供了更多(实现定义的)可能性。
相关部分(C11中的第5.1.2.2.1节,但此特定方面与C99相同)说明:
程序启动时调用的函数名为main。该实现声明此函数没有原型。它应该使用int的返回类型定义,并且没有参数:
int main(void) { /* ... */ }
或者有两个参数(这里称为argc和argv,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):
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]
指向的字符串表示程序参数。- 参数
argc
和argv
以及argv
数组指向的字符串应该可由程序修改,并在程序启动和程序终止之间保留它们最后存储的值。
请注意,这适用于托管环境,您通常在C程序中看到的环境。独立环境(例如嵌入式系统)的约束要少得多,如同标准的5.1.2.1中所述:
在独立环境中(可以在没有操作系统任何好处的情况下执行C程序),程序启动时调用的函数的名称和类型是实现定义的。除了第4章要求的最小集合之外,任何可用于独立程序的库设施都是实现定义的。
对于托管环境(这是正常环境),C99标准说:
5.1.2.2.1 Program startup
程序启动时调用的函数名为
main
。该实现声明此函数没有原型。它应该用返回类型int
定义,没有参数:int main(void) { /* ... */ }
或者有两个参数(这里称为
argc
和argv
,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):int main(int argc, char *argv[]) { /* ... */ }
或等效的; 9)或其他一些实施定义的方式。
9)因此,
int
可以被定义为int
的typedef名称替换,或者argv
的类型可以写为char **argv
,依此类推。
C11和C18标准与C99标准基本相同。
C ++ 98标准说:
3.6.1 Main function [basic.start.main]
1程序应包含一个名为main的全局函数,它是程序的指定开始。 [...]
2实现不应预定义主要功能。此功能不应过载。它应具有int类型的返回类型,否则其类型是实现定义的。所有实现都应允许以下两个主要定义:
int main() { /* ... */ }
和
int main(int argc, char* argv[]) { /* ... */ }
C ++标准明确地说“它[主函数]应该具有int类型的返回类型,但是其类型是实现定义的”,并且需要与C标准相同的两个签名。因此,C ++标准直接不允许'void main()',尽管没有什么可以阻止非标准的符合实现允许替代(也不是标准的符合实现允许替代作为标准的扩展)。
C ++ 03,C ++ 11,C ++ 14和C ++ 17标准与C ++ 98基本相同。
传统上,Unix系统支持第三种变体:
int main(int argc, char **argv, char **envp) { ... }
第三个参数是一个以null结尾的字符串指针列表,每个字符串都是一个环境变量,它有一个名称,一个等号和一个值(可能是空的)。如果你不使用它,你仍然可以通过'extern char **environ;
'进入环境。很长一段时间,它没有声明它的标题,但POSIX 2008标准现在要求它在<unistd.h>
中声明。
这被C标准认可为附录J中记录的共同扩展:
J.5.1 Environment arguments
¶1在托管环境中,main函数接收第三个参数
char *envp[]
,该参数指向以null结尾的指向char
的指针数组,每个指针都指向一个字符串,该字符串提供有关此程序执行环境的信息( 5.1.2.2.1)。
Microsoft VS 2010编译器很有趣。该网站说:
main的声明语法是
int main();
或者,可选地,
int main(int argc, char *argv[], char *envp[]);
或者,
main
和wmain
函数可以声明为返回void
(无返回值)。如果将main
或wmain
声明为返回void,则不能使用return语句将退出代码返回到父进程或操作系统。要在main
或wmain
声明为void
时返回退出代码,必须使用exit
函数。
我不清楚当void main()
的程序退出时会发生什么(退出代码返回到父代或o / s) - 而且MS网站也是静默的。
有趣的是,MS没有规定C和C ++标准所要求的main()
的双参数版本。它只规定了一个三参数形式,其中第三个参数是char **envp
,一个指向环境变量列表的指针。
微软页面还列出了一些其他选择 - wmain()
,它采用宽字符串,还有更多。
Microsoft VS 2005版本的this page没有列出void main()
作为替代方案。来自Microsoft VS 2008的versions确实如此。
int main()
和int main(void)
一样吗?有关详细分析,请参阅我对What should main()
return in C and C++的回答结束。 (似乎我曾经认为这个问题提到了C ++,尽管它没有,也从来没有。在C ++中,int main()
和int main(void)
之间没有区别,int main()
是惯用的C ++。)
在C中,两种符号之间存在差异,但您只能在深奥的情况下注意到它。具体来说,如果你从你自己的代码中调用main()
函数就会有所不同,你可以在C中调用它并且不允许在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中都有效,即使它们之间存在细微差别。
POSIX支持execve()
,而int main(int argc, char *argv[], char *envp[])
又支持
http://en.wikipedia.org/wiki/Main_function_(programming)#C_and_C.2B.2B
添加的参数是环境,即NAME = VALUE形式的字符串数组。
int main(int argc, char *argv[])
除了通常的int main(int argc, char **argv, char **envp)
和POSIX int main(int argc, char* argv[], char* envp[], char* apple[]);
之外,在Mac OS X上也支持
int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);
当然它只是Mac版。
在Windows上有
WinMain
作为Unicode(实际上是宽字符)变体。当然还有int main(void)
。
int main(int argc, char **argv, char **envp)
在某些操作系统(例如,Windows)下,这也是有效的:
envp
其中getenv()
提供了一个环境,否则可以通过qazxswpoi访问