在main函数执行之前和执行之后执行的方法
来源:互联网 发布:mac怎样下载msoffice 编辑:程序博客网 时间:2024/05/01 05:43
原文网址:
http://my.opera.com/sharpwiner/blog/2006/12/26/main
http://club.topsage.com/thread-282994-1-1.html
通过指定
static void before(void) __attribute__ ((constructor));
表明这个函数应该在main之前执行
static void after(void) __attribute__ ((destructor));
表明函数在main之后执行
atexit表明函数在退出的时候执行
static void before(void) __attribute__ ((constructor));
表明这个函数应该在main之前执行
static void after(void) __attribute__ ((destructor));
表明函数在main之后执行
atexit表明函数在退出的时候执行
#include <stdio.h>#include <stdlib.h>static void before(void) __attribute__ ((constructor));static void after(void) __attribute__ ((destructor));static void middle(void);static void before(){ fprintf(stderr, "In %s %d\n", __func__, __LINE__);}static void after(){ fprintf(stderr, "In %s %d\n", __func__, __LINE__); system("pause");}static void middle(){ fprintf(stderr, "In %s %d\n", __func__, __LINE__);}int main(){ atexit(middle); system("pause"); return 0;}
囫囵C语言(三):谁调用了我的 main?
现在最重要的是要跟得上潮流,所以套用比较时髦的话,谁动了我的奶酪。谁调用了我的 main?不过作为计算机工作者,我劝大家还是不要赶时髦,今天Java热,明天 .net 流行,什么时髦就学什么。我的意思是先花几年把基本功学好,等你赶时髦的时候也好事半功倍。废话不多说了。
我们都听说过一句话:“main是C语言的入口”。我至今不明白为什么这么说。就好像如果有人说:“挣钱是泡妞”,肯定无数砖头拍过来。这句话应该是“挣钱是泡妞的一个条件,只不过这个条件特别重要”。那么上面那句话应该是 “main是C语言中一个符号,只不过这个符号比较特别。”
我们看下面的例子:
/* file name test00.c */
int main(int argc, char* argv)
{
return 0;
}
编译链接它:
cc test00.c -o test.exe
会生成 test.exe
但是我们加上这个选项: -nostdlib (不链接标准库)
cc test00.c -nostdlib -o test.exe
链接器会报错:
undefined symbol: __start
也就是说:
1. 编译器缺省是找 __start 符号,而不是 main
2. __start 这个符号是程序的起始点
3. main 是被标准库调用的一个符号
再来思考一个问题:
我们写程序,比如一个模块,通常要有 initialize 和 de-initialize,但是我们写 C 程序的时候为什么有些模块没有这两个过程么呢?比如我们程序从 main 开始就可以 malloc,free,但是我们在 main 里面却没有初始化堆。再比如在 main 里面可以直接 printf,可是我们并没有打开标准输出文件啊。(不知道什么是 stdin,stdout,stderr 以及 printf 和 stdout 关系的群众请先看看 C 语言中文件的概念)。
有人说,这些东西不需要初始化。如果您真得这么想,请您不要再往下看了,我个人认为计算机软件不适合您。
聪明的人民群众会想,一定是在 main 之前干了些什么。使这些函数可以直接调用而不用初始化。通常,我们会在编译器的环境中找到一个名字类似于 crt0.o 的文件,这个文件中包含了我们刚才所说的 __start 符号。(crt 大概是 C Runtime 的缩写,请大家帮助确认一下。)
那么真正的 crt0.s 是什么样子呢?下面我们给出部分伪代码:
///////////////////////////////////////////////////////
section .text:
__start:
:
init stack;
init heap;
open stdin;
open stdout;
open stderr;
:
push argv;
push argc;
call _main; (调用 main)
:
destory heap;
close stdin;
close stdout;
close stderr;
:
call __exit;
////////////////////////////////////////////////////
实际上可能还有很多初始化工作,因为都是和操作系统相关的,笔者就不一一列出了。
注意:
1. 不同的编译器,不一定缺省得符号都是 __start。
2. 汇编里面的 _main 就是 C 语言里面的 main,是因为汇编器和C编译器对符号的命名有差异(通常是差一个下划线'_')。
3. 目前操作系统结构有两个主要的分支:微内核和宏内核。微内核的优点是,结构清晰,简单,内核组件较少,便于维护;缺点是,进程间通信较多,程序频繁进出内核,效率较低。宏内核正好相反。我说这个是什么目的是:没办法保证每个组件都在用户空间(标准库函数)中初始化,有些组件确实可能不要初始化,操作系统在创建进程的时候在内核空间做的。这依赖于操作系统的具体实现,比如堆,宏内核结构可能在内核初始化,微内核结构在用户空间;即使同样是微内核,这个东东也可能会被拿到内核空间初始化。
随着 CPU 技术的发展,存储量的迅速扩展,代码复杂程度的增加,微内核被越来越多的采用。你会为了 10% 的效率使代码复杂度增加么?要知道每隔 18 个月 CPU 的速度就会翻一番。所以我对程序员的要求是,我首先不要你的代码效率高,我首先要你的代码能让 80% 的人迅速看懂并可以维护。
总结:
main函数执行之前,主要就是初始化系统相关资源:
1.设置栈指针
2.初始化static静态和global全局变量,即data段的内容
3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容
4.运行全局构造器,估计是C++中构造函数之类的吧
5.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数
现在最重要的是要跟得上潮流,所以套用比较时髦的话,谁动了我的奶酪。谁调用了我的 main?不过作为计算机工作者,我劝大家还是不要赶时髦,今天Java热,明天 .net 流行,什么时髦就学什么。我的意思是先花几年把基本功学好,等你赶时髦的时候也好事半功倍。废话不多说了。
我们都听说过一句话:“main是C语言的入口”。我至今不明白为什么这么说。就好像如果有人说:“挣钱是泡妞”,肯定无数砖头拍过来。这句话应该是“挣钱是泡妞的一个条件,只不过这个条件特别重要”。那么上面那句话应该是 “main是C语言中一个符号,只不过这个符号比较特别。”
我们看下面的例子:
/* file name test00.c */
int main(int argc, char* argv)
{
return 0;
}
编译链接它:
cc test00.c -o test.exe
会生成 test.exe
但是我们加上这个选项: -nostdlib (不链接标准库)
cc test00.c -nostdlib -o test.exe
链接器会报错:
undefined symbol: __start
也就是说:
1. 编译器缺省是找 __start 符号,而不是 main
2. __start 这个符号是程序的起始点
3. main 是被标准库调用的一个符号
再来思考一个问题:
我们写程序,比如一个模块,通常要有 initialize 和 de-initialize,但是我们写 C 程序的时候为什么有些模块没有这两个过程么呢?比如我们程序从 main 开始就可以 malloc,free,但是我们在 main 里面却没有初始化堆。再比如在 main 里面可以直接 printf,可是我们并没有打开标准输出文件啊。(不知道什么是 stdin,stdout,stderr 以及 printf 和 stdout 关系的群众请先看看 C 语言中文件的概念)。
有人说,这些东西不需要初始化。如果您真得这么想,请您不要再往下看了,我个人认为计算机软件不适合您。
聪明的人民群众会想,一定是在 main 之前干了些什么。使这些函数可以直接调用而不用初始化。通常,我们会在编译器的环境中找到一个名字类似于 crt0.o 的文件,这个文件中包含了我们刚才所说的 __start 符号。(crt 大概是 C Runtime 的缩写,请大家帮助确认一下。)
那么真正的 crt0.s 是什么样子呢?下面我们给出部分伪代码:
///////////////////////////////////////////////////////
section .text:
__start:
:
init stack;
init heap;
open stdin;
open stdout;
open stderr;
:
push argv;
push argc;
call _main; (调用 main)
:
destory heap;
close stdin;
close stdout;
close stderr;
:
call __exit;
////////////////////////////////////////////////////
实际上可能还有很多初始化工作,因为都是和操作系统相关的,笔者就不一一列出了。
注意:
1. 不同的编译器,不一定缺省得符号都是 __start。
2. 汇编里面的 _main 就是 C 语言里面的 main,是因为汇编器和C编译器对符号的命名有差异(通常是差一个下划线'_')。
3. 目前操作系统结构有两个主要的分支:微内核和宏内核。微内核的优点是,结构清晰,简单,内核组件较少,便于维护;缺点是,进程间通信较多,程序频繁进出内核,效率较低。宏内核正好相反。我说这个是什么目的是:没办法保证每个组件都在用户空间(标准库函数)中初始化,有些组件确实可能不要初始化,操作系统在创建进程的时候在内核空间做的。这依赖于操作系统的具体实现,比如堆,宏内核结构可能在内核初始化,微内核结构在用户空间;即使同样是微内核,这个东东也可能会被拿到内核空间初始化。
随着 CPU 技术的发展,存储量的迅速扩展,代码复杂程度的增加,微内核被越来越多的采用。你会为了 10% 的效率使代码复杂度增加么?要知道每隔 18 个月 CPU 的速度就会翻一番。所以我对程序员的要求是,我首先不要你的代码效率高,我首先要你的代码能让 80% 的人迅速看懂并可以维护。
总结:
main函数执行之前,主要就是初始化系统相关资源:
1.设置栈指针
2.初始化static静态和global全局变量,即data段的内容
3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容
4.运行全局构造器,估计是C++中构造函数之类的吧
5.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数
- 在main函数执行之前和执行之后执行的方法
- 在main函数执行之前和执行之后执行的方法<转载>
- 在main函数执行之前和执行之后执行的方法
- 在main函数执行之前和之后执行一段代码
- 在main函数之前和之后执行一些操作
- 如何使得代码在main函数之前/之后执行
- c/c++怎样在程序的入口处main()函数之前和之后执行另外的自定义函数
- mian函数之前执行函数,和main函数之后执行函数
- main函数之前执行
- 在main()之前执行
- 在main函数之前执行一些函数
- 一个c程序在执行main函数之前和main之后都做了那些事情啊
- static变量在Main函数之前执行
- static变量在Main函数之前执行
- 什么会在main函数之前执行
- 让自己的函数在main函数之前执行
- __attribute__((constructor)) 修饰的函数在main函数之前执行
- 可以在main函数之前执行的函数
- redhat5中文乱码问题解决
- 手机病毒原理
- Window API For Config Files
- ACM列车长的烦恼(C语言实现)
- 解析江民杀毒软件反病毒核心技术
- 在main函数执行之前和执行之后执行的方法
- 补10.17Servlet 登录注册案例 连接数据库
- 主动防御型杀毒软件的技术探讨
- 精短高效的XML解析器,纯C单一程序,应用于银行的国税库行横向联网接口系统中,稳定可靠,运行速度飞快
- 使用智能指针的一个示例
- Linux Hacker必备工具-nmap
- vim 建工程
- Android面试系列之一
- Siri将改变人们的生活