一.main()函数是什么样的
我们先要搞清楚main()函数有哪几种?
查阅C89/C99/C11标准文档,里面明确固定了两种写法:
int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }
除此之外,其他写法应该都是不规范的写法,常见的有以下几种
1、main()
直接的mian()并没有返回值,没有入参。这种写法实际来说,部分编译器会显示警告,并且会返回默认值为int。不过在C89标准中其实是可以的,由于没有声明返回类型,所以才会返回默认值int。
2、void main()
初学者经常会使用的形式,但是并不知道来源在哪。这种写法的返回值是void,没有参数。值得注意的是,一旦声明是void,在程序退出后,想要获取其退出状态也就不可以了。
3、int main(void)
比较常见的写法,这种写法的形参为void,表明它在调用的时候不能传入任何参数,那么它也就不能获取命令行参数了。
4、int main ()
和上面第3种看起来好像没啥区别,但是还是有些许不同。main函数虽然声明为无入参,但调用时却是可以传入任何参数或不传参数的。
5、int main(int argc,char *argv[])
int argc入参为命令行参数个数,char *argv[]入参为命令行参数数组。这种写法也比较常见的,主要用在需要从命令行获取参数的功能。
6、int main(int argc,char *argv[],char *envp[])
包含三个参数的一种写法,上面第5种的升级版,int argc是命令行参数个数,char *argv[]是命令参数数组,char *envp[]是环境变量数组。虽然只比第六种多了一个参数,但全局变量environ可以代替envp的作用,获取或者设置环境变量可以使用getenv或putenv,因此也没有必要使用该形式。这种写法多源于编译器的扩展。
写法多样有些算是历史遗留有些算是编译器的扩展,还有些不知道从哪里生出来的。为了代码的通用可移植性,建议采用C89/C99/C11标准文档中规定的这两种写法。
二.谁在调用main()函数,是否必须有main()函数
1、编译链接时的引导代码。操作系统的应用程序其实在mian执行前也需要运行一段引导代码才可以执行main,我们写应用程序的时候不需要考虑引导代码。编译链接时(准确说是链接)由链接器中事先准备好的引导代码给链接进去和我们写的应用程序一起构成最终的可执行程序。
2、运行时的加载器。加载器是操作系统中的程序,当我们去执行一个程序时,加载器负责将这个程序加载到内存中去执行这个程序。
3、程序在编译链接时使用链接器,运行时使用加载器,这两个东西对程序运行原理非常重要。
上面一段解释,相信大家已经明白了,是否叫main()函数取决于我们编译特别是链接时指定的入口函数,如何调用完全由操作系统。很简单的一个道理,比如我事先写好了调用“usrapp”函数,那么你在写函数体的时候名字就必须叫usrapp,而我如果改成叫"usrapp1"的函数,你在写函数体的时候就必须写成“usrapp1”,同样的道理,操作系统在某种情况下找main函数,此时你就应该写"main"的函数名,如果操作系统在其他的情况下找“WinMain”或者“WinMain2”的时候,你自然就应该把入口函数写成“WinMain”或者“WinMain2”了。那么这里写成"main"不行,写成“WinMain”却可以,就不难理解了。
所以说必须有main函数只是针对windows操作系统而已,其他操作系统是允许我们在链接时,修改链接选项,制定我们程序的入口函数,此时入口函数就可以任由我们发挥了,只需要符合变量命名规则即可,虽然是这样,但是在整个工程中,还是必须只能有一个入口函数,只是名字换了而已。
声明:
本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。