我们知道在 C 语言中,程序是从 main 函数开始运行的,我们称其为主函数。我们来看看下面几种 main 函数定义正确吗?
那么 main 函数的原型到底是什么呢?我们来看看编译器怎么说,我们分别编译下四种 main
函数的形式,经过编译后,程序可以编译通过并且执行完成。那么最标准的 main 函数的原型是上面的第四种,main 函数是操作系统调用的函数,操作系统总是将 main 函数作为应用程序的开始并且将 main 函数的返回值作为应用程序的退出状态。那么 C 编译器为什么要支持这么多不同的 main 函数原型呢?我们来做个实验,代码如下
#include <stdio.h> int main() { printf("hello\n"); return 99; }
我们在 BCC 编译器下编译看看,结果肯定是打印 hello 了。但是我们返回的是 99,我们顺便打印下环境变量的值,看看有什么玄机
我们看到打印的环境变量的值为 99。如果我们将上面程序中的 return 后面改成 0。再来编译看下环境变量的值是多少
我们看到环境变量的值变成 0 了。那么 main 函数的返回值是将它返回到系统中并保存下来。那么回到我们之前所说的问题,在以前的程序中,好多中编程写法。我们为了兼容以前所有的程序,编译器就必须得支持所有的 main 函数的写法。那么程序执行时可以向 main 函数传递参数,格式:int main(int argc, char *argv[], char *env[])。a> argc - 命令行参数个数;b> argv - 命令行参数数组;c> env - 环境变量数组;我们平时见到的大多数是带前两种的 main 函数的写法。
那么在gcc编译器中,常见用法如下:
我们下来看个示例代码,代码如下
#intclude <stdio.h> int main(int argc, char* argv[], char* env[]) { int i = 0; printf("============== Begin argv ==============\n"); for(i=0; i<argc; i++) { printf("%s\n", argv[i]); } printf("============== End argv ==============\n"); return 0; }
我们来看看编译效果
我们可以看到打印出了 ./a.out。也就是说打印出了除过 gcc 以外的命令行参数,我们再以下面这种方式来打印呢
那么我们可以看到打印出了除 gcc 以外的所有参数。讲到最后,我们再来讨论个有意思的问题:main 函数一定是程序执行的第一个函数吗?咋一听,就是啊,我们平时书上所见到的,还有老师说的都是这样的哈。那么我们来做个实验,代码如下
#include <stdio.h> #ifndef __GNUC__ #define __attribute__(x) #endif __attribute__((constructor)) void before_main() { printf("%s\n",__FUNCTION__); } __attribute__((destructor)) void after_main() { printf("%s\n",__FUNCTION__); } int main() { printf("%s\n",__FUNCTION__); return 0; }
我们看到如果是 GUNC 编译器的话,便定义 __attribute__ 宏。通过这个宏,我们分别声明了两个函数,我们来看看编译结果
我们看到竟然在 main 函数的前后分别执行了这两个函数。感觉很神奇,那么这个 __attribute__ 宏便是我们 gcc 编译器所特有的属性关键字。使用就可以在 main 函数的执行前后再去执行别的函数。我们再来看看在 BCC 编译器中,它还支持吗
我们看到它不支持那个 __FUNCTION__ ,我们便将他换成对应的字符串。编译后的结果是只打印了 main,也就是说它在 main 函数前后并没有去执行那两个函数。所以这个特性也是编译器特有支持的,但起码说明了在现代编译器中支持在 main 函数前调用其他函数。
欢迎大家一起来学习 C 语言,可以加我QQ:243343083。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。