void main(void){}
在C语言里面也是可以编译运行的,因为C语言的函数只看名字,不看返回类型,程序在寻找入口函数的时候只是寻找叫做“main"的函数,并不在乎它的返回类型和参数类型。
这也就是C语言不允许函数重载的原因,同名函数只是参数不同,在C语言眼里就是重复的函数符号。
C语言是调用者清栈,所以main函数不写参数也可以,比如 main(void),不会运行出错,只是函数里拿不到命令行参数,但是压栈的参数还是会被正确处理
汇编层面的所谓返回值就是 函数返回的时刻 EAX 寄存器的值,无论如何EAX寄存器里总是有值的,你不去给它赋值它就是个随机数,所以即使 void main(..)也有返回值,只是随机值而已。
C语言设计上有很多不太严谨的地方,有些是早期编译器遗留的问题,大家还是要按照现代C语言规范去写代码,可读性可维护性才能更好
虽然main函数结束后程序进程也就结束了,你的代码的确不需要main函数的返回值,但是这个值还是有意义的,它会作为进程结束的状态码,返回给父进程。Unix体系特别喜欢把进程当作函数来调用,多个命令行程序组合级联来实现功能,所以启动子进程后就要用进程返回值来获取子进程是否运行正确的状态。
复习下,main函数的正确写法
int main(int argc, char *argv[]) { return 0; }
这个问题下许多人都是答非所问或者带着恶意乱猜的,从微软到NeXT的官方文档里,大概从1988年开始大量的资料里的C代码都有出现void main() 或者 void main(void)的写法,几乎成了一种工程上的约定俗成,这真的就没有意义吗?还有甩锅给谭C的,更是无稽之谈,难道微软和Borland的工程师也是跟谭C学的?
在搞明白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/rivest/Md5.c
1988年NASA的并行矩阵乘法代码:https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19890017256.pdf
1990年斯坦福线性加速实验室的论文:https://www.slac.stanford.edu/cgi-bin/getdoc/slac-pub-5251.pdf
1990年惠普实验室的期刊 https://www.hpl.hp.com/hpjournal/pdfs/IssuePDFs/1990-06.pdf
1996年,SAS C编译器手册 https://support.sas.com/documentation/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成为了“事实标准”。
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有