main()在C ++中是否已重载?


69

main()存在2个有效版本C++

int main()  // version 1
int main(int argc, char **argv)  // version 2

但是,两个过载不能同时存在。为什么不?(可能的用例:从终端运行程序时,如果未传递任何参数,则调用第一个版本,否则调用第二个版本。)

编译器是否执行特殊检查以允许每个二进制文件仅允许一个版本?


8
通过阅读您的问题,甚至我也很想知道这一点
Devjosh 2011年

8
投票(不会有什么区别,只供您注意),当它是纯C ++问题(即C不支持重载,标题和第一行使其明确表示)时,用“ C”标记问题是C ++)。避免在功能明显不同的问题中混用不同语言。
大卫·罗德里格斯(DavidRodríguez)-dribeas 2011年

4
@David,我故意放下C标签,因为main()也允许使用多个版本C。此外,void main()C ++不支持,但大多数情况下它是有效的C。但是,提到C++这个问题,我已经站在立场上了。
iammilind

10
void main()如果您谈论的是标准C(C89,C90,C99),它也不是有效的C。
Nawaz

3
“如果不传递任何参数,则应将第一个版本称为第二个版本”。被调用的是程序包含的那个。如果程序包含无参数版本,则忽略命令行参数。如果程序包含第二个版本且没有参数,argc则为1,并argv包含指向程序名称的指针,后跟一个空指针。因此,即使您可以重载它,也不会想要这种行为,因为即使没有参数,仍然会有一个argc / argv对。
史蒂夫·杰索普

Answers:


65

§3.6.1/ 2(C ++ 03)说

实现不得预定义main功能。此功能不得重载。它的返回类型应该是int类型,否则它的类型是实现定义的。所有实现应允许以下两个main定义:

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

您可以使用它们之一。两者均符合标准。

另外,由于char *argv[]等效于char **argv,所以替换char *argv[]char **argv没有任何区别。


但是两个版本不能同时共存!(用例可能是这样的:从命令提示符运行二进制文件时,如果不传递任何参数,则应将第一个版本称为第二个版本)。

不可以。两个版本不能同时共存。一个程序可以只具有一个main功能。哪一个,取决于您的选择。如果要处理命令行参数,则必须选择第二个版本,否则第一个版本就足够了。另请注意,如果您使用第二个版本,并且不传递任何命令行参数,则其中没有任何危害。它不会引起任何错误。你只需要解释argcargv相应,并根据自己的价值,你写的逻辑和程序的流程。


5
鉴于该问题已标记了2种语言,因此您所引用的标准尚不清楚....
Tony Delroy11年

17
@Tony:考虑到问题实际上是关于重载s的,而C不支持重载,我只能假设C标签被滥用了。好吧,标题和第一行的确说明了C ++的讨论。
大卫·罗德里格斯(DavidRodríguez)-dribeas 2011年

5
@Tony:我现在提到了。另外,要This function shall not be overloaded清楚说明其C ++。毕竟,C不支持重载任何功能。
Nawaz

2
@Tonymain并不是真正的程序入口点,它是第一个(main)要调用的函数,但是必须 main调用之前进行静态初始化。我怀疑,DOS / Windows系统有不同的入口点的应用程序(如果有不同的可执行文件格式可能是),我也怀疑,在的情况下wmain_tmainWinMain该程序不包含一个普通的main功能(在库定义在联)转发该呼叫......但我必须有一个Windows环境实际测试,所以我不会断言这是真实的或者
dribeas大卫-罗德里格斯

1
David关于Windows入口点如何工作的猜测是完全正确的。main库代码中隐藏了一个普通的函数。在_tWinMain你看到的东西是不是官方的切入点,它只是尽可能的入口点你的代码而言。
科迪·格雷

20

Windows和Unix具有:

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

和Win32应用具有:

int WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

MacOS具有:

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

不要忘记,这main通常不是操作系统在执行程序时首先要调用的东西。该main函数是运行时环境调用的函数。通常在一些元数据中声明要执行的第一条指令的地址,通常在可执行文件的开头声明。

据我所知,只要有一个,以上都不与C / C ++标准相抵触,这是有道理的,因为如果有多个,操作系统将不知道要调用哪个。在编译器中不检查只有一个,在链接器中检查。


2
我想知道,可以将MSVC视为不符合wrtWinMain吗?由于进入函数被定义为main...(除了MSVC中所有其他不兼容的内容。)
Xeo

3
@Xeo:这基本上是极限... VS所做的就是main为您创建一个函数,该函数在调用您的WinMain函数之前进行一些特定的初始化。程序的入口点仍然是main,只是在这种情况下它不是您的主要入口。似乎与第3.6.1 / 2节矛盾。实现不应预定义主要功能。,但如果他们可以确保它不会影响您的程序(即,如果您确实定义了main它使用的是您的版本而不是其自己的版本),那么它的行为就好像if一样,就足够了。
大卫·罗德里格斯(DavidRodríguez)-dribeas 2011年

1
...并且与此同时,其他库的功能也完全相同(main如果需要,大多数单元测试框架都将为您提供。这时,它成为关于main编译器生成还是链接为库的哲学讨论。。和所有是灰色的,我不会真的在意它,我已经在其他地方看到更糟糕的事情... Symbian C ++的人是一个
dribeas大卫-罗德里格斯

MSVC也有int wmain(int argc, wchar_t* argv[]);_tmain: - / -看到stackoverflow.com/questions/895827/...
托尼德尔罗伊

@David:好吧,如果图书馆提供的话main,按照标准是可以的。:)
Xeo

13

C ++ Standard 1998和2003版本的3.6.1.2节规定:

实现不得预定义主要功能。此功能不得重载。它的返回类型应该是int类型,否则它的类型是实现定义的。

进一步,

ISO C ++标准(ISO / IEC 14882:1998)特别要求main返回int。它对格式正确的程序有明确的“应”约束。

第3.6.1节¶2:

它的返回类型应该是int,否则它的类型是实现定义的。所有实现应允许以下两个main定义:

int main() { /* … */ }

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

因此main,标准允许两个版本的版本,并且使用哪个版本作为程序员的实现偏好。


1
Nitpick:通常在编译器+工具集实现的上下文中使用实现细节,而在这种情况下,由实现的用户决定:即程序员。
DavidRodríguez-dribeas 2011年

@DavidRodríguez-dribeas:指出了。我对implementation detail在编译器和工具集的上下文中或以通用方式显式使用时感到有点困惑。以通用方式使用它,您做到了!:)
Alok保存

9

Main定义于C天。它按照printf的规则进行设置。考虑main为方差函数:

int main(...)

该标准说没有参数和两个指针参数都可以。但是,如果实现要提供更多的参数,则实现是可以自由提供的。

您不能拥有两个mains的原因与您无法printf在C程序中两次定义一个类似函数的原因相同。当然,printf支持不同的参数,并根据其中存在哪些参数来更改其行为,但是就C ++而言,它不会超载。


+1好的参考点;将注意力集中在区别上:例如,...允许调用者改变参数数量,但是可以期望OS加载程序始终main使用相同数量的参数进行调用。如果程序未明确列出(int argc, char* argv[])大多数实现,则无论如何都会隐式地考虑它们。它们要放入的寄存器和/或堆栈可能在调用main之前加载了它们的值。值得庆幸的是,您不会收到有关未使用变量的警告:-)。因此,与“ printf ...改变其行为”相比,main可能是恒定的(但正式意义上是确定的)
Tony Delroy11年

7

标准说main不能过载。它不会被破坏,并且不能有两个具有相同名称的函数。我猜这将导致链接失败,但是编译器可能希望添加显式检查,以便提供更清晰的错误消息。

int main(int argc, char **argv)并且int main()应该是它的首选签名,但是编译器可以自由接受main带有不同参数的。


这是否意味着main始终声明extern "C",无论您是否明确编写?
Kerrek SB 2011年

@iammilind:我无法在标准中检测到这样的要求,如果存在,我会感到惊讶,因为您不能main直接从任何上下文(甚至是操作系统)中调用,因为操作系统必须调用专门生成的静态初始化main之前的代码-即它是一个实现细节,详细说明了如何进行改编,可以进行特殊改编,也可以完全不进行改编。
DavidRodríguez-dribeas 2011年

@David,我没有提到标准,但我是根据观察结果说的。第一件事是main()直到名称在全局范围内,名称才会混乱;第二件事是,当您main()在一个文件中声明多个具有不同参数的文件时,编译器会给出以下错误:error: declaration of C function int main() conflicts with ...
iammilind

1
@iammilind:这仅意味着平台中的编译器将其main视为C函数,而不是一般而言“它不会被视为C函数而被破坏”或“它始终是extern "C"”。特别是在平台(OS)中,称为C样式函数main作为程序入口点,C ++编译器将被迫将您的main函数修改为其他内容,并向_main符号添加静态初始化。未指定此名称的原因是因为它正在处理与OS的接口,并且C ++标准无法强制执行该操作。
大卫·罗德里格斯(DavidRodríguez)-dribeas 2011年

0

因为不能在C ++中重载main()。编译器显示以下错误:

error C2731: 'main' : function cannot be overloaded 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.