读书笔记_运行库的初始化和清理

 

运行库的初始化和清理

编译器会为每个模块自动插入一个“编译器编写”的入口函数,在这个入口函数中进行好各种初始化工作后再调用用户的入口函数,在用户的入口函数返回后在运行自己的清理函数,我们把编译器插入的这个入口函数称为CRT入口函数

Exe模块的入口函数

用户入口函数

CRT入口函数

应用

main

mainCRTStartup

控制台程序

wmain

wmainCRTStartup

宽字符的控制台程序

WinMain

WinMainCRTStartup

Win32应用程序

wWinMain

wWinMainCRTStartup

宽字符的Win32应用程序

DLL模块的用户入口函数是DllMain,因为DllMain没有字符类型的参数,所以对于宽字符(Unicode)的DLL模块,其入口函数也是DllMain。

         编译器为DLL模块准备的CRT入口函数是_DllMainCRTStartup函数,其函数原型与DllMain完全相同。

在链接阶段,模块的入口函数是被注册到目标程序文件(PE文件)中的,默认情况下,链接器会将CRT入口函数注册为模块入口,这样在执行的过程中首先执行的是CRT的入口函数,对CRT进行初始化的,等用户的入口函数返回后,CRT的入口函数可以执行清理工作。

此外,链接器支持通过参数 /ENTRY: function选项指定其他函数作为入口。如果在项目链接属性中(output)将Entry-point symbol 指定为WinMain函数名,或者直接在命令行参数中加入/ENTRY: “WinMain”, 那么就将WinMain函数设置为程序的入口了。此时就必须要用户自己考虑如何初始化和清理运行库了。

下面来看以一个进程中的多个模块都使用运行库的情况。对于静态链接运行库德程序模块,不论是EXE还是DLL,每个模块内部都复制了一份运行库的变量和代码,这样每个模块中都有一个运行库的实例。当进程中有多个运行库实例时,每个运行库实例会各自使用自己的数据(变量)和资源(堆),理论上是可以正常工作的。但有时也可能引发问题,其中之一就是从一个CRT堆分配的内存被送给另一个CRT实例来释放,在调试版本中CRT的内存检查功能会发现这一问题并报告错误。但在发布版本中,这将会导致严重的问题。

运行检查是指运行期间对其进行的各种检查,主要是为了发现运行时所暴露的各种错误, run-time errors。编译器通常采取如下几种措施

1.  使用调试版本的支持库和库函数,调试版本的库函数包含了更多的调试支持和检查功能。比如调试版本的内存分配和释放函数会插入额外的信息来支持各种内存检查功能。

2.  在编译时插入额外代码对栈指针、局部变量等进行检查。

3.  提供断言(ASSERT),报告(_RPT)等机制让程序员在编写程序时加入检查代码和报告运行期错误。

前两种是编译器行为,第三种需要手动插入。

下面以VC8的编译器为例,来看自动运行期检查能够发现的运行期错误:

1.  栈指针被破坏(Stack pointer corruption),负责栈指针检查的函数是_RTC_CheckEsp.

2.  分配在栈上的局部变量越界(Overruns),以及因此而导致的栈被破坏(Stack corruption)

3.  依赖未初始化的局部变量,负责该功能的RTC函数是_RTC_UninitUse,如果程序中使用了没有初始化的局部变量,那么编译器在编译期会给出C4700或C4701号警告,但这两个警告属于第4级别的警告(Level 4 Warning),所以有可能被屏蔽掉或被忽视。如果启用了/RTCu开关,当程序运行到使用未初始化过的局部变量时,会弹出错误报告对话框。

4.  因为赋值给较短的变量而导致数据丢失,负责该项检查的RTC函数是_RTC_Check_x_to_y,其中x和y可以是8,4,2,1几个值的组合。

5.  使用堆有关的错误。

关于断言,VC编译器的断言是_ASSERT和_ASSERTE,MFC框架定义了ASSERT宏和VERIFY宏,标准C中也提供了一个assert(全小写)的宏,使用方法基本相同。

 

当发现错误后,主要通过函数_CrtDbgReport进行报告,断言失败和_RPT宏都是通过调用_CrtDbgReport函数报告调试信息的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值