为什么主函数没有定义为`main(std::vector<std::string> args)`?

15

这个问题只是半开玩笑的。我有时做梦都想过没有裸数组或C字符串的世界。

如果你在使用C++,那么main函数的首选定义应该是什么样的呢:

int main(std::vector<std::string> args)

为什么没有一个符合C++精神的main版本,已经有多个定义可以选择了呢?


3
实现者可以自由提供其他签名作为 main,只要它们都返回一个 int。因此,一个更好的问题可能是为什么他们不这样做? - Dennis Zickefoose
9个回答

11
因为C++的设计是(几乎)向后兼容C代码。
尽管 C 代码在 C++ 编译器中会出现问题,但这种情况相对罕见,而且通常有一个很好的理由需要这种破坏性的更改。
但是,虽然更改main函数的签名对我们来说很方便,但并不是必需的。对于从C移植代码的人来说,这只是另一件你必须改变的事情,没有特别的收益。
另一个原因是std::vector是一个库,而不是核心语言的一部分。因此,在每个C++程序中都必须#include 。
当然,在C++的早期阶段,它没有vector。因此,当向语言添加vector时,他们可以更改main函数的签名,但那样会破坏不仅C代码,而且还会破坏所有现有的C++程序。
值得吗?

4
我们已经有多种main函数的定义可以选择了,为什么不添加一个类似于C++的版本呢? - Inverse
7
可以做到。但是这样真的值得麻烦吗?你可以只需将程序的第一行改为 std::vector<std::string> args(argv, argv+argc)。标准委员会更喜欢只在新功能相比库方法有显著优势时才将其添加到语言中。 - jalf
是因为编译STL本身需要标准库,而标准库又调用main函数吗? - Chubsdad
4
标准库不会调用 main 函数。 - GManNickG
4
请注意,main 的多个版本都使用 C 调用约定彼此兼容。如果 RTL 调用 main(argc, argv, envp),而你提供的函数只是 main(int, char*[]),那么额外的第三个参数会被安全地忽略。可以编写一个 RTL,始终调用一个单一版本的 main,而不考虑你提供的哪个版本。但是 main(vector<string>) 与其他版本不兼容,因此 RTL(已经编译在单独的 .o 文件中)需要知道你在源代码中提供了什么。 - Rob Kennedy
显示剩余2条评论

11
除了兼容C之外,还有另一个原因。在C++中,标准库被认为是完全可选的。C++语言本身并没有强制要求您使用标准库中的东西,例如std::stringstd::vector,这是完全按设计来的。事实上,按设计来说,您应该能够使用标准库的某些部分而无需使用其他部分(尽管这导致了一些一般令人讨厌的事情,如std::ifstreamstd::ofstream操作const char* C风格字符串,而不是std::string对象)。
理论上,您应该能够使用C++语言,并与其搭配任何您想使用的对象、容器等库,可以是标准库,也可以是专有库(例如Qt、MFC),或者是您自己创建的库。如果将定义main以接受标准库中定义的类型的参数,就会破坏这个设计目标。

1
除此之外,仍然存在像std::type_info这样的东西,它被非标准语言特性所使用。 - tc.
但是 OP 询问的是是否有一种选项可以这样定义 main()。如果可能的话,您仍然可以拥有 C 风格的 main(),而没有标准库。 - einpoklum

5
因为它会强制你包含 <vector><string>

2
此外,它会强制你使用与运行时库相同的 <vector><string> 实现。 - Mike Seymour
@Mike:但是您不一定需要从运行时库中输入 main。如果编译器生成了一个秘密函数,由运行时库找到并将C参数转换为您选择的C ++类型,然后调用实际的 main,就不应该有冲突。除非我漏掉了什么,否则这将是一个完全透明的更改。 - Dennis Zickefoose
3
然而,您已经可以选择至少2个main()变体。添加一个特定于C ++的变体并不一定意味着您必须使用它(现有选项仍然可以作为选项)。这可能会使编译器/链接器需要支持正确调用main()所需的机制变得更加复杂,但这并非不可能。我不是说它一定值得代价和复杂性 - 只是说它不是不可能的。 - Michael Burr
你甚至可以更进一步,编译器可以允许任何单个参数,只要它可以从一对双向迭代器构造。int main(T args); int _Main(argc, argv) { return main(T(argv, argv + argc)); } - Dennis Zickefoose
总结@MichaelBurr的评论:不,它不会强制你包含那个。这将是一个选项。 - einpoklum

4

像 @jalf 一样,我有时也会写下

int main(int argc, char** argv) {
    std::vector<std::string> args(argv, argv+argc);

但是,像其他人所说的那样,main函数必须兼容C语言。我认为它是操作系统运行时的接口,而这些操作系统(至少在我使用的系统中)都是用C编写的。

尽管有些开发环境鼓励使用替代函数,如wmain_tmain。您可以编写自己的编译器/IDE,以鼓励使用 int vmain(const std::vector<std::string>& args)


1
运行时已经需要了解一些关于C++的知识,以创建和销毁静态对象并处理未捕获的异常。因此,允许C++特定变体的main不会是一个巨大的飞跃;唯一真正的反对意见是你必须标准化vectorstring的实现。 - Mike Seymour
@Mike Seymour:我想你是对的。然后问题就出现了,为什么要使用std::basic_string<char>和std::vector?我会投票支持int main(std::initializer_list<std::initializer_list<CharT>>) - Cubbi
1
更进一步,只需在您的编辑器/IDE中拥有一个main()片段,它什么也不做,只返回cppMain(vector<string>(argv, argv+argc));,并将cppMain()用作程序的“可定制”起点。我可能会开始使用这个... - Michael Burr

4
我一直担心的问题是,一旦允许使用复杂类型,就会出现在类型构造函数中抛出异常的风险。而且,目前语言设计上绝对没有办法捕获这样的异常。如果决定要捕获这些异常,那么委员会和编译器编写者需要做更多的工作,这比仅仅说“允许std::vector<std::string>>”要麻烦得多。
可能还有其他问题。整个“与运行时不兼容”的问题似乎对我来说有点牵强附会,因为您现在可以通过宏提供基本相同的功能。但这种情况要更加复杂。

回答晚了,但我认为这是最好的。真正的问题不在于与C或包含文件的兼容性,而在于异常的可能性。 - Inverse
1
基本上,在构建std::vector和构建字符串指针数组以及它们所指向的空终止字符串之间,抛出异常的机会几乎是相同的。 - einpoklum

3
因为 C++ 存在的时间比 C++ 标准长,并且深度依赖于 C。同时,像原始 ANSI C 标准一样,将现有实践编码是其中重要的部分。
如果改变某些有效的东西没有意义,特别是如果这会破坏大量现有的代码。
即使是经历了相当多次迭代的 ISO C,仍然非常重视向后兼容性。

2

基本上,为了保持与C的兼容性。如果我们放弃这一点,main()函数将被移入一个类中。


18
你为什么要把主函数移到类里面?这样做甚至没有任何意义。Java 和 C# 这样做是因为语言不允许非成员函数存在,但这并不代表这是一个好的设计决策。 - jalf

2
main()的多个定义实际上并不是真正的多个定义。有三种:
  • int main(void)(C99)
  • int main(int argc, char *argv[])(C99)
  • int main(int argc, char *argv[], char *envp[])(POSIX,我想)
但在POSIX中,你只能真正地得到第三个。你可以调用带有额外参数的函数是由于C调用约定。
除非内存布局以可移植的方式神奇地兼容,否则你不能拥有extern "C" int main(std::vector<std::string> argv)。运行时将使用错误的参数调用main()并失败。这没有简单的解决方法。
相反,如果main()不是extern "C",运行时可以尝试按顺序使用各种支持的符号,直到找到一个为止。我想main()默认是extern "C",而且你不能重载extern "C"函数。
更多乐趣,请点击void main(void)

似乎这是VC++的一个特性。它的实现方式并不明显(可能链接到了不同的运行时库?)。 - tc.

1

我会尽可能用最好的句子来解释。

C++ 的设计是向后兼容 C,std::vector 是包含在一个只有在 C++ 中才被包含的库中的。

此外,C++ 和 C 程序都是设计为在 shell 或命令行(Windows、Linux、Mac)中运行的,操作系统将参数作为字符串数组传递给程序。那么操作系统如何真正地翻译向量呢?

这是我能想到的最主要的原因,欢迎批评。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接