繁体   English   中英

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

[英]What are the valid signatures for C's main() function?

C 中 main function 的有效签名到底是什么? 我知道:

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

还有其他有效的吗?

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 条要求的最小集合之外,任何独立程序可用的库设施都是实现定义的。

标准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 主函数【basic.start.main】

1 程序应包含一个名为 main 的全局函数,它是程序的指定开始。 [...]

2 实现不应预定义主函数。 该函数不得重载。 它应该有一个 int 类型的返回类型,否则它的类型是实现定义的。 所有实现都应允许以下两个 main 定义:

 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) { ... }

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

这被 C 标准认可为通用扩展,记录在附件 J 中:

###J.5.1 环境参数

¶1 在托管环境中,主函数接收第三个参数char *envp[] ,该参数指向指向char以空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 的退出代码是什么void main() ——而且 MS 网站也保持沉默。

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

Microsoft 页面还列出了一些其他替代方案 — wmain()接受宽字符串,等等。

此页面的 Microsoft VS 2005 版本未列出void main()作为替代方法。 Microsoft VS 2008 以后的版本都可以。

int main()int main(void)吗?

有关详细分析,请参阅我对C 和 C++ 中main()应该返回什么的回答的结尾。 (似乎我曾经认为这个问题是指 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):并且正式地编译器不应该抱怨到拒绝的程度编译代码,尽管它可能会合理地抱怨(警告您)(并且将-Werror与 GCC 一起使用会将警告转换为错误)。 如果你使用int main(void) ,随后对main()调用应该会产生一个错误——你说这个函数不接受参数,但试图提供三个参数。 当然,在声明或定义main()之前,您不能合法地调用它(除非您仍在使用 C90 语义)——并且实现没有声明main()的原型。 注意:C11 标准在不同的示例中说明了int main()int main(void) — 两者在 C 中都是有效的,即使它们之间存在细微差别。

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

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

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

http://en.wikipedia.org/wiki/Main_function_(编程)#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。

在 Windows 上有

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

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

int main(void)

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM