分享
 
 
 

静态对象、全局对象与程序的运行机制

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

静态对象、全局对象与程序的运行机制

1、 在介绍静态对象、全局对象与程序的运行机制之间的关系之前,我们首先看一下atexit函数。

atexit函数的声明为:int atexit( void ( __cdecl *func )( void ) );

参数为函数指针,返回值为整型,0表示成功,其他表示失败。当程序运行结束时,他调用atexit函数注册的所有函数。如果多次调用atexit函数,那么系统将以LIFO(list-in-first-out)的方式调用所有的注册函数。

举例如下(代码摘自MSDN):

#include <stdlib.h>

#include <stdio.h>

void fn1( void ), fn2( void ), fn3( void ), fn4( void );

void main( void )

{

atexit( fn1 );

atexit( fn2 );

atexit( fn3 );

atexit( fn4 );

printf( "This is executed first.\n" );

}

void fn1()

{

printf( "next.\n" );

}

void fn2()

{

printf( "executed " );

}

void fn3()

{

printf( "is " );

}

void fn4()

{

printf( "This " );

}

编译、运行程序后,程序的输出为:

This is executed first.

This is executed next.

注册函数的顺序为:fn1、fn2、fn3、fn4,但是调用顺序为fn4、fn3、fn2、fn1。

2、理解了atexit函数之后,我们就可以来看看局部静态对象了。

class AAA{ … } ;

AAA* createAAA()

{

static AAA a ;

return &a ;

}

在调试状态下,汇编代码如下(请观察蓝色标记出来的代码):

AAA* createAAA()

{

static AAA a ;

[1] 00401056 call AAA::AAA (4010A0h)

[2] 0040105B push offset `createAAA'::`2'::a::`dynamic atexit destructor' (442410h)

[3] 00401060 call atexit (409A50h)

00401065 add esp,4

00401068 mov dword ptr [ebp-4],0FFFFFFFFh

return &a ;

0040106F mov eax,offset a (452620h)

}

00401091 ret

注:[1]、[2]、[3]为方便说明加入的字符,实际代码中并不存在。

[1]语句很明显的调用AAA的构造函数。

[2]语句将442410h压入栈中。

[3]语句调用atexit函数,根据我们的了解,atexit的参数应该是函数指针。那么我们来分析一下442410h处的代码,从注释来看,我们看到了destructor。代码如下:

`createAAA'::`2'::a::`dynamic atexit destructor':

[1] 0044242E mov ecx,offset a (452620h)

[2] 00442433 call AAA::~AAA (403A90h)

0044244B ret

[1]语句将a的地址放在ecx寄存器中,这是this调用规范的风格。

[2]语句调用AAA的析构函数。

程序结束时,将调用atexit函数注册的442410h处的函数,进而调用了AAA的析构函数。从而保证了析构函数的调用。

3、 了解了局部静态对象之后,我们来看看全局对象。

我们知道全局对象必须在main函数前已经被构造。为了弄清楚全局对象何时被构造,我在全局对象的实例化处设置了断点,调用堆栈如下:

static.exe!aaaa::`dynamic initializer'() Line 22

C++

static.exe!_initterm(void (void)* * pfbegin=0x00451038, void (void)* * pfend=0x00451064) Line 707

C

static.exe!_cinit(int initFloatingPrecision=1) Line 208 + 0xf bytes

C

static.exe!mainCRTStartup() Line 266 + 0x7 bytes

C

作为对比,我在AAA的析构函数出设置了断点,调用堆栈如下:

static.exe!AAA::~AAA() Line 19

C++

static.exe!aaaa::`dynamic atexit destructor'() + 0x28 bytes

C++

static.exe!doexit(int code=0, int quick=0, int retcaller=0) Line 451

C

static.exe!exit(int code=0) Line 311 + 0xd bytes

C

static.exe!mainCRTStartup() Line 289

C

由此我们可以看出程序的实际入口点位mainCRTStartup而不是main函数(相对于ANSI的控制台程序而言)。

我们来分析一下_cinit函数:

注释中有一句[3. General C initializer routines],看来该函数的功能之一是完成C的初始化例程。

函数的核心代码如下:

/*

* do initializations

*/

initret = _initterm_e( __xi_a, __xi_z );

/*

* do C++ initializations

*/

_initterm( __xc_a, __xc_z );

看来该函数主要进行C、C++的初始化。我们进一步分析函数_initterm_e和_initterm,两个函数的功能进本相同,都是遍历函数指针(由参数指定函数指针的开始位置[__xi_a、__xi_z]、结束位置[__xc_a、__xc_z]),如果函数指针不为null,那么调用该函数。

那么__xi_a、__xi_z和__xc_a、__xc_z到底代表了什么呢?在cinitexe.c文件中有如下代码:

#pragma data_seg(".CRT$XIA")

_CRTALLOC(".CRT$XIA") _PVFV __xi_a[] = { NULL };

#pragma data_seg(".CRT$XIZ")

_CRTALLOC(".CRT$XIZ") _PVFV __xi_z[] = { NULL };/* C initializers */

#pragma data_seg(".CRT$XCA")

_CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { NULL };

#pragma data_seg(".CRT$XCZ")

_CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { NULL };/* C++ initializers */

#pragma comment(linker, "/merge:.CRT=.data")

可以看出这四个变量分别在数据段.CRT$XIA、.CRT$XIZ、.CRT$XCA、.CRT$XCZ中。当连接器布局代码时,它按根据的名称,按照字母排序的规则,排列所有段。这样在段.CRT$XIA中的变量出现在段.CRT$XIZ所有变量之前,从而形成链表。对于.CRT$XCA、.CRT$XCZ数据段同理。最后这四个数据段被合并到.data数据段中。

再看看这些变量的类型,typedef void (__cdecl *_PVFV)(void); 所以这些变量组成了2个初始化函数指针链表。

调试过程中,看到__xc_a、__xc_z链表中,指向的初始化函数很多是构造函数,如:

static std::_Init_locks initlocks;

static filebuf fout(_cpp_stdout);

extern _CRTDATA2 ostream cout(&fout);

cout对象也在此时被构造。

对于析构函数的调用也是采用相同的方式,只是此时每一种初始化,都有一种终止函数与之对应。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有