您的位置:首页 > 编程语言 > C语言/C++

C++--编译器工作原理

2015-06-05 16:19 639 查看
编译器:我们常用的编译器一般有Visual Studio(Windows),Xcode(OS),GCC(Unix)等。它们的主要功能就是把我们写的高级代码转换成可执行的二进制程序。这个转换过程主要通过预处理器,编译器和链接器完成,同时它们也是可以分别设置属性,用来控制代码的生成方式。1,预处理器设置:如一些平台相关的宏设置,通过控制这些宏定义,来编写跨平台代码。(而且现代的预处理器,还可以直接通过命令行来定义预处理宏这与代码中编写#define指令等效) 2,编译器设置:主要包括是否产生调试信息,是否展开内联函数等一系列优化代码的操作。3,链接器设置:主要是设置链接那些可执行文件,以及指定程序库搜索路径,还有一些链接优化方式等。

以VS为例谈谈编译的具体过程:从你敲代码,到真正运行起来,一般有预编译,编译,链接,加载,这几步。首先是预编译阶段,主要是对c,cpp或asm等源文件进行整理,主要包括将头文件拷贝到源文件中(#include),将代码中的宏定义替换和条件编译等。然后就是编译阶段,主要将整理好的源文件编译成一个个obj文件(unix是.o文件),这时已经是二进制机器码了,只是还没有决定代码内存地址。再链接阶段,把这些obj链接得到exe可执行文件,这时机器码在内存中的相对基址已经确认了。最后由操作系统加载exe,把这些可执行的二进制代码全部加载进内存,绝对基址才最终确认,即内存地址确认。从而得到进程,即我们程序的运行。

动态链接库(dll)与静态链接库(lib):(1)首先你能调用一个函数,前提就是它在内存里存在。一般的函数,编译链接之后,在exe里面。操作系统加载exe的时候,分配内存,然后把函数代码放在这块内存,所以你就能直接调用函数了。(2)dll的话,不一样。这是把一些代码跟程序主体分开,编译链接为dll。加载exe的时候,dll可能尚未加载,这时,你想调用的函数不在内存里。你可以手动用LoadLibrary这个函数手动加载dll,然后这个函数就在内存里了,可以取得它的地址,然后就可以调用。但一般编译器会帮我们在使用时自动加载dll,其底层实现无非也是这么操作的(类似系统底层对main函数的调用)。因此,dll的加载其实就类似函数的调用,它能节省内存。(3)lib的话,正好相反,即把lib库拷贝一份到exe里面,这样与一般的编译过程差不多了,可以脱离库使用,类似内联。(4)之所以使用库,主要就是方便以后复用,节省编译时间,因为这些库都是已经编译好的二进制文件。

注释:对于c++项目理论上也是可以像脚本一样做动态更新的,因为dll与exe主体本来就是分开的,我们可以只更新dll来实现动态更新。但是很不方便,因为exe这个主体已经不能再修改,如果dll中改了某些数据的结构,那么exe中原来的调用就不行了,除非只改了逻辑,所以要用这种就得严格控制统一的接口,而且以后也不能扩展。

c++自己定义好了一套准则,所有编译器都要遵循这个规则,至于编译器底层具体怎么去运行实现它们这个不确定,但最终的结果要遵循这个定好的标准。现在的编译器大都也没能全部实现c++的所有标准。所以对于一些未定义的行为,不同的编辑器就可能会有不同的表现。所以很多问题不能只死认VS,不同环境实现可能不同。

应用程序在内存中一般分为几块区域:

全局数据区:存放全局数据,静态数据等

代码区:代码存放区域

栈区:局部变量

堆区:动态内存

常用辅助工具

一,检测哪些代码比较耗性能的剖析工具:1,Intel的VTune软件,执行效率高但不够详细。2,IBM的Rational Quantify软件,执行效率低但够详细。3,微软混合了前两种的优点,开发了名为LOP的剖析器。当然还有很多,就不一一列举了。通过这些工具我们就可以针对性的优化代码了。

二,检测内存泄露工具:IBM的Purify Plus工具套装中的Rational Purify。Purify须在程序运行前安插监控代码,为所有指针解引用及内存分配与释放代码中加入挂钩(钩子函数)。在Purify下运行代码,能现场报告代码中的及时潜在问题。程序结束后,也能产生详尽的内存泄露报告。(另一个流行工具:Compuware公司的Bounds Checker,和Purify类似)

钩子函数:(1)百科上说,它是Windows消息处理机制的一部分,通过设置“钩子”,应用程序可以在系统级对所有消息、事件进行过滤(即截取系统消息),访问在正常情况下无法访问的消息。钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。通俗点讲就是类似一个回调函数,为某些事件设置了钩子,只要对应事件触发就会截取这个事件响应。总的来讲,钩子就是用来截取Windows消息,再用钩子函数回调出去。一些外挂,木马等就是利用它实现的。(2)举例说明:钩子就是,本来A调用B结果你写一个新的函数C,强行替换掉B,A以为自己调用了B,其实调用的是C,当然C也可以再回过去调用B。比如你输入密码,本来这消息直接通知到控件,但是现在有人挂了钩子,密码就通知到他,然后他再转发给控件。肉眼看上去一切正常,但是你的密码已经被窃听了。再如,通过这方法,也可以盗取游戏的图片、模型等资源,写一个函数,替换掉glTexImage2D。

注:部分内容前面C++基本数据类型一章也有提及,这里再做总结。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: