当前位置: 华文问答 > 数码

C 语言的「void main」是怎么一代代传下来的?

2020-01-20数码

这个问题下许多人都是答非所问或者带着恶意乱猜的,从微软到NeXT的官方文档里,大概从1988年开始大量的资料里的C代码都有出现void main() 或者 void main(void)的写法,几乎成了一种 工程上的约定俗成 ,这真的就没有意义吗?还有甩锅给谭C的,更是无稽之谈,难道微软和Borland的工程师也是跟谭C学的?

NeXTSTEP文档中的void main

在搞明白void main的来历之前,我们必须要先搞明白在(C89之前的)早期的C语言实现中,void关键字以及void作为返回的函数,比如void somefunc()是怎么来的,定义是什么,使用的场景是什么,再去考虑使用以void作为返回的主函数,也就是void main()的原因。C89标准翻遍也未必给你答案,因为在电脑编程这样的领域, 工程实践是早于行业标准的,编译器的实现就是使用者的标准。

1989年一份介绍Microsoft Quick C升级的介绍里,屏幕上的截图写道

Returns : a pointer to void if successful , or NULL if not .

这段说明很显然是来自Quick C的某个帮助文档的,成功就返回void的指针,失败则返回空。虽然不是用void做main的返回值,但我们看到void作为返回值确实有其应用场景的。

我们再往前追,1988年9月份的PC Magazine,看到了void main的写法,不得不说那个时代的电脑杂志真硬核,各种代码

不知不觉间我们已经逼近void指针发明的时候了,在The Art of UNIX Programming一书中层介绍到void指针起源于将C标准化的努力

在C++的发明者Bjarne Stroustrup的文章Sibling Rivalry: C and C++中,提到了「古典C语言」的概念,Steve Johnson(yacc的发明人)开发的PCC(Portable C Compiler)添加了void,枚举类型和struct,它们在ANSI标准之前被广泛使用。

然后再往后看,我们就看到了大量以void开头的函数

这样看来,C语言中使用void作为返回值或许是受到C++的前身C with classes的影响,而理由则是类型安全

Whatever the origin, what was implemented in C with classes was a simple type-safe notion of memory holding objects of unknown type. Any pointer can be implicitly converted to void*, and any use of the memory referred to by a void* involves a cast to some type.
无论起源如何,在C with classes中实现的都是一个简单的类型安全的概念,用于存储未知类型的对象。任何指针都可以隐式转换为void *,并且对void *所引用的内存的任何使用都涉及到将其转换为某种类型。

但是我们还是不清楚void main的最初起源是哪里,它出现在RSA的md5代码里,出现在NASA的文档里,出现在斯坦福线性加速实验室的论文里,出现在惠普开发的早期的motif代码里,出现在SAS C编译器的手册里,它出现的平台跨越了DOS、Unix、Commodore 64、Amiga OS乃至Cray超级电脑,它注定是某种「事实标准」而不是个别工程师的错误

1990年RSA的MD5实现:https:// people.csail.mit.edu/ri vest/Md5.c

1988年NASA的并行矩阵乘法代码:https:// ntrs.nasa.gov/archive/n asa/casi.ntrs.nasa.gov/19890017256.pdf

1990年斯坦福线性加速实验室的论文:https://www. slac.stanford.edu/cgi-b in/getdoc/slac-pub-5251.pdf

1990年惠普实验室的期刊 https://www. hpl.hp.com/hpjournal/pd fs/IssuePDFs/1990-06.pdf

1996年,SAS C编译器手册 https:// support.sas.com/documen tation/onlinedoc/sasc/doc650/clug.pdf

我目前能找到的最早的带有void main的手册是1985年一系列MetaWare High C编译器的手册,在High C Programmer's Guide和High C Library Reference Manual里都出现了带有void main的例子。

而更多的例子,出现在Lattice AmigaDOS C Compiler手册里,Lattice C Compiler是非常著名的微处理器C编译器,早期的Microsoft C Compiler就是从它贴牌而来,而对于Amiga平台来说Lattice C Compiler则是默认的C编译器。

上面的截图中「Returns」(返回)一节提到,「If you want to pass a non-zero termination code back to AmigaDOS, use the exit or _exit function」,非零的返回值不能直接由main函数返回,而需要调用额外的函数。这或许就是当时没有用int main的理由。

在1988年的Turbo C Reference Guide中,我们同样看到void main的出现,由于Turbo C在IBM PC开发者之间非常流行,最终void main成为了「事实标准」。