软件调试笔记29

来源:互联网 发布:见过好听的名字 知乎 编辑:程序博客网 时间:2024/06/15 18:04

C/C++运行库

编译器在将高级语言编译到低级语言的过程中,比较复杂的运算符对应比较多的低级语言指令,为了防止指令段多次重复,编译器通常将他们封装为函数,将高级语言翻译成对应的函数调用,比如VC编译器通常把new, delete编译为malloc 和free函数的调用。这些相配套的函数库或者类库称为支持库support library或者运行库runtime library,比如C标准定义的标准C函数,C++标准定义的C++标准类库等。实现支持库是实现编译器的一项重要任务。


C运行库

C标准定义了C库函数的原型和功能,但没有提供实现,这个任务留给了编译器,每个编译器实现的通常是标准C函数库的一个超级,称为C支持库或者C运行库,简称CRT。主要函数如下,



C++标准库

由三大部分组成:C标准库,IO流和标准模板库STL。VC编译器是将c++编译器所使用的C标准库与C编译器所使用的C运行库一起实现,而把IO流和STL单独实现。


链接运行库

为了满足不同的需要,运行库通常有多个版本,比如为了辅助调试的版本,包含了断言,内存检查等功能,这些不会放在发布版本。调试版本和发布版本是共享源代码的,只是.lib和DLL文件不同。


静态链接和动态链接

程序能顺利运行,使用运行库的程序在运行时必须可以找到库中的函数,有静态链接和动态链接两种方法。静态链接就是将使用的库函数复制到程序文件中,称为本模块的代码,但是会导致一个进程内的多个模块中,某些运行库函数重复存在于多个模块。动态链接在程序运行时动态加载包含支持函数的DLL,并更新程序的IAT表,使程序可以顺利调用DLL的支持函数。可以通过编译器选项来设置链接支持库的方式。/MT代表静态链接,/MD代表动态链接。如果使用调试版本则加d, 比如/MTd。


运行库的初始化




DLL模块的用户入口函数是DllMain。 


编译器支持通过/ENTRY:function来指定其他函数作为入口。


初始化

CRT入口函数主要包括以下:



可以在自己的程序文件中注册初始化和清理函数,比如以下例子,



多个运行库实例

对于静态链接的程序模块,每个模块内都复制了一份运行库的变量和代码(部分),也就是每个模块中都有一个运行库的实例。当进程中有多个运行库实例时,每个都有自己的数据和资源(堆),有时候可能引发问题,比如从弄个一个CRT堆分配的内存被送给另一个CRT实例来释放。在调试版本中,CRT的内存检查功能会发现这个问题并报告错误,但是发布版本,便会导致严重的问题。


运行期检查

运行期检查是位了发现程序运行时所暴露出的各种错误,即运行期错误。编译器通常采取如下几种措施:



前两种是编译器的运行库和编译过程自动提供的,称为编译器的自动检查,第三种需要人为插入代码来调用编译器提供的宏或函数,称为手工插入的检查,比如_ASSERT和—_RPT等。


自动的运行期检查



断言ASSERT



_ASSERT, _ASSERTE区别就是后者会把断言表达式也显示出来。


注意:断言不会出现在发布版本,所以不能在里面改变变量值,比如自增,可以使用VERIFY宏,因为它的表达式在发布版本一样会编译进目标代码。


报告运行期检查错误

_CrtDbgReport是报告运行期检查信息的一个主要函数,



可以把调试信息送往三个目的地:调试文件,调试器的监视窗口和调试消息对话框。可以通过专门的函数来设置。