虚空主体的起源是什么

What is the origin of void main?

本文关键字:起源 是什么 主体      更新时间:2023-10-16

我经常在论坛上看到臭名昭著的void main(),问题后几乎立即有评论告诉用户永远不要使用void main()(我完全同意)。但是void main()的起源在哪里呢?

为什么我仍然看到更新的人养成了让main什么都不回的坏习惯,而正确的方法是返回int。我理解为什么这个问题和其他许多问题中解释的这种方法是错误的,但我不知道这种声明main的方法是如何产生的,甚至不知道为什么它仍然被教授给一些学生。

甚至Bjarne Stroustrup也用C++编写了void main,所以它确实是一个常见的反模因,而且是一个古老的反模因为,早于Java和其他支持void main的当代语言。当然,Bjarne也写过void main从来都不是C或C++的一部分。然而,对于后一种说法(在他的常见问题解答中),至少从C99开始,Bjarne似乎是错误的,因为C99标准的N869草案在其§5.1.2.2.3/1中规定

“如果main函数的返回类型是与int兼容的类型,则从初始调用到main函数的返回相当于以main函数返回的值作为参数调用exit函数;到达终止CCD_ 16功能的CCD_。如果返回类型与int不兼容,则返回到主机环境的终止状态未指定”

之前,在其§5.1.2.2.1/1中,它说明了main的签名,

“或者以某种其他实施方式定义的方式”

返回类型“与int不兼容";例如可以是void

因此,虽然这不是一个完整的答案(我怀疑网上是否有关于这一点的历史来源),但至少它在一定程度上纠正了问题的假设。CCD_ 21在C和C++中并不是一个完全可憎的东西。但在C++中,它是无效的:它是托管C++实现中不支持的C东西。

我一直是这个问题的受害者,所以我想我可以告诉你为什么会发生这种情况。在我们的C课程中,教师必须使用示例程序(可能是"Hello World")开始我们的课程,为此他们必须使用main()方法。

但是,由于他们不想混淆学生,也不想在C编程课程一开始就陷入教授返回类型和返回语句的复杂性,他们使用(也要求我们使用)void main(),并告诉我们在详细研究函数和返回类型之前,假设这是默认类型。

因此,这导致我们养成了一个错误的习惯,即在C编程的第一堂课上使用void main()。

希望这能很好地解释为什么大多数计算机程序员,尤其是那些新来的程序员会采用这种糟糕的做法。

干杯,马扬克

我个人认为如下:K&RC不需要指定返回类型,并隐式地假设它是int,同时K&R没有使用返回值。

例如,K&R第一版如下:

#include <stdio.h>
main() 
{
printf("Hello Worldn");
}

因此,难怪后来读到这篇文章的人(在一些编译器将void类型作为扩展添加到语言中之后)认为main实际上有一个void返回语句。。我也会做同样的事。

实际上K&R稍后会说:

为了简洁起见,我们省略了到目前为止,我们的主要功能,但我们将包括它们此后,作为程序应返回其状态的提醒环境

所以这只是另一个例子,说明当你写了不正确的代码,并假设人们在做愚蠢的事情之前会阅读所有内容,随后会包含免责声明时会发生什么;)

作为众多作家中的一位,Herbert Schildt写了一些流行但不一定是高质量的书,这些书都支持这一想法。

一个令人震惊的例子是他的注释C标准。他在左侧页面引用了ISO/IEC 9899:1990标准,并在右侧页面提供了注释。当他引用第5.1.2.2.1节程序启动时,上面写着:

程序启动时调用的函数名为main。该实现没有声明此函数的原型。它可以在没有参数的情况下定义:

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

或者有两个参数(…):

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

这不包括添加到C99中的"或以某种其他实现定义的方式"子句。

然后,在注释中,他说:

有趣的是,编译器没有声明main()的原型。因此,您可以根据程序的要求自由声明main()。例如,这里有三种常见的声明main()的方法:

void main(void)  /* no return value, no parameters */
int main(void)   /* return a value, no parameters */
/* return a value and include command-line parameters */
int main(int argc, char *argv[])

C90标准不允许第一种变体,尽管他这么说,但无辜的读者可能会感到困惑。

请注意,第5.1.2.2.3节程序终止说明:

main函数的初始调用返回相当于用main函数返回的值作为参数调用exit函数。如果main函数执行的返回没有指定任何值,则返回到托管环境的终止状态是未定义的。

由于您会发现exit采用int参数,因此可以清楚地看出,main的返回类型应该是int

评论说:

在大多数实现中,main()的返回值(如果有)会返回到操作系统。请记住,如果您没有显式返回main()中的值,那么从技术上讲,传递给操作系统的值是未定义的。尽管当没有指定其他返回值时(即使main()被声明为void),大多数编译器都会自动返回0,但您不应该依赖这一事实,因为标准并不能保证这一点。

这些评论中有很多是牛粪,我并不是唯一一个持这种观点的人。这本书唯一的优点是,它包含了几乎所有的C90标准(fprintf的描述中少了一页——同一页打印了两次),远远低于该标准的成本。有人认为,价格的差异代表了评论中的价值损失。关于C的一些信息,请参阅Lysor,以及Clive Feather对注释C标准的评论。

他的另一本书是《C:完整参考》,该书至少出版了第4版。第三版广泛使用CCD_ 39;这可能在第4版中得到了澄清,但令人遗憾的是,花了这么多版本才纠正了这样一个根本问题。

在裸机上运行的嵌入式程序,也就是说,在没有操作系统的情况下,永远不会返回。上电时,重置向量间接跳到main(首先发生一些内存初始化),在main内部,有一个无限的while (1){}循环。从语义上讲,main的返回值没有意义。

可能的原因:

  • Java程序员习惯于编写public static void main(...)
  • 缺少return语句可能会导致一些人认为main不会返回,尽管它隐式返回0
  • 在C中,您可以编写不带返回类型的main(),默认情况下为int。也许有些人认为缺少的返回类型等同于void
  • 坏书/老师

从C++的角度来看,存在3个混淆源:

  • 原教旨主义PC/台式机程序员,他们狂热而盲目地宣扬int main(),而实际上自己并不了解标准的全貌。C和C++对于如何在独立系统中声明main()有完全不同的规则(当编程裸金属嵌入式系统或操作系统时)
  • 与C++相比,C语言在历史上有着不同的规则。在C中,main()的规则随着时间的推移而发生了变化
  • 来自黑暗时代的遗留编译器和编码标准,包括20世纪80年代的编程教师

我将在这个答案中解决每一个困惑的来源。

PC/桌面程序员有问题,因为他们认为托管系统是唯一存在的系统,因此传播关于main()的正确形式的不正确/不完整的宣传,教条地说你必须使用int main(),在这样做的时候错误地引用了标准(如果有的话)。

C和C++标准总是列出两种类型的系统:独立系统和托管系统。

在独立实现中,void main (void)在C中一直是允许的。在C++中,独立实现略有不同:独立实现可能不命名入口函数main(),或者它必须遵循返回int的声明形式。

即使是Bjarne Stroustrup也无法引用标准或正确/完整地解释这一点,所以难怪普通程序员会感到困惑!(他引用了托管环境子章节,但没有引用其中的所有相关部分)。

这一切都在这里详细讨论,并参考了标准,Bjarne和其他人请阅读。

关于托管系统中的void main (void),这源于ISO C标准之前黑暗时代的某个地方,在那里一切都是允许的。

我怀疑它背后的罪魁祸首是Borland Turbo C编译器,它在1990年发布ISO C时已经是市场领导者。此编译器允许void main (void)

需要注意的是,用于托管实现的void main (void)在C90中被隐式禁止。对于托管系统,不允许任何实现定义的形式。因此Turbo C从来都不是一个严格符合要求的实现。然而,它仍然在学校中使用(尤其是在印度)!从头开始教每个学生不正确的编程标准。

自从C99以来,void main (void)和其他形式在C中被允许使用,因为添加了一句奇怪的话:"或者以其他实现定义的方式"。这也在上面的链接答案中进行了讨论,参考了C99的基本原理和C标准的其他部分,这些部分假设托管系统main()可能不会返回int。

因此,在C中,void main (void)(可以说)目前是托管实现的一种允许形式,因为编译器记录了它的功能。但请注意,由于这是实现定义的行为,是编译器决定是否允许这种形式,而不是程序员

在C++中,void main (void)是不允许的形式。