C++ 编译,运行过程 详解。

要更深入了解C++, 必须要知道一个程序从开始到结束都干了些什么, 怎么干的。 所以我从C++编译到运行过程,解析下程序是怎么跑的。

首先,初略的说一下之前C++的编译过程,C++编译过程包括预编译-》汇编-》编译-》链接。称为一个可执行文件。(Windows平台下为.exe文件)。

预编译主要展开包含的头文件,宏定义等操作。例如一个简单的main程序,编译预编译后,的文件对比。

 
可以看到里面的宏已经被去掉了。如果定了那个宏,那么宏里面的内容也会显示出来。头文件也是,如果你包含了你一个.h 文件,那么整个.h文件会包含进来。

汇编过程,就是把已经预编译的文件编译成汇编代码的过程,整个过程会包含语法,词法的分析,和一些优化操作。

编译过程其实是跟汇编可以合成一个阶段,变成目标代码。也就是二进制文件。

链接过程是将单个编译后的文件链接成一个可执行程序。前面的预编译、汇编、编译都是正对单个文件,以一个文件为一个编译单元,而链接则是将所有关联到的编译后单元文件和应用的到库文件,进行一次链接处理,之前编译过的文件 如果有用到其他文件里面定义到的函数,全局变量,在这个过程中都会进行解析。

首先看看编译后的文件样子(已VS2012编译后的OBJ文件为例子,不同编译器 样式可能会不同。)

编译前的文件

#include "Car.h"

int main(int argc, char* argv[])

{

Car* p = new Car();

delete p;

return 1;

}

编译后的样子(由于编译后的文件 信息太多 只贴出里面未解析符号部分。)

UNDEF:00002DC4 ; int __thiscall Car::Car(Car *__hidden this)

UNDEF:00002DC4                 extrn [email protected]@[email protected]:near ; CODE XREF: _main+63p

UNDEF:00002DC8 ; int __thiscall Car::~Car(Car *__hidden this)

UNDEF:00002DC8                 extrn [email protected]@[email protected]:near

UNDEF:00002DC8                                         ; CODE XREF: Car::`scalar deleting destructor‘(uint)+26p

UNDEF:00002DCC ; __fastcall _RTC_CheckStackVars(x, x)

UNDEF:00002DCC                 extrn @[email protected]:near

UNDEF:00002DCC                                         ; CODE XREF: std::_String_alloc<0,std::_String_base_types<char,std::allocator<char>>>::_Alloc_proxy(void)+68&#24;p

UNDEF:00002DCC                                         ; $LN19+72&#24;p ...

UNDEF:00002DD0 ; __fastcall __security_check_cookie(x)

UNDEF:00002DD0                 extrn @[email protected]:near

UNDEF:00002DD0                                         ; CODE XREF: [email protected]@[email protected]@[email protected]@[email protected]+F&#24;p

UNDEF:00002DD0                                         ; [email protected][email protected]@@[email protected]@[email protected][email protected]@@@[email protected]@[email protected]@[email protected]@Z+F&#24;p ...

UNDEF:00002DD4 ; __stdcall _CxxThrowException(x, x)

编译后的文件用(用反汇编成汇编代码查看) 其中实现函数会变成一堆汇编指令。而那些引用到的在其他文件里面实现的函数将会变成一个特点的符号(如上面中的调用Car类的构造函数 extrn
[email protected]@[email protected]:near)这些符号称做为解析的符号,表示在链接的时候需要被解析。符号的生成名称具体跟编译器有关,但是会保证一个类的某个函数名称在同一个编译里面必须是唯一的,因为我们在预编译阶段已经把Car.h包含进来所以编译器能正确生成这个函数的名字,然后在链接的时候 会找到改名字的函数,把此标识名字替换为函数的地址。这样就实现的链接。

在符号解析(symbol resolution)阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合;(2)集合U是未解析符号(unresolved symbols,比如已经被引用但是还未被定义的符号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始,E、U、D都是空的。

(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到U、D集合中,然后处理下一个输入文件。

(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把 m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point),此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。

(3): 如果处理过程中往D加入一个已存在的符号,或者当扫描完所有输入文件时U非空,链接器报错并停止动作。否则,它把E中的所有目标文件合并在一起生成可执行文件。



版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-18 12:19:00

C++ 编译,运行过程 详解。的相关文章

Java编译程序和运行过程详解

java整个编译以及运行的过程相当繁琐,我就举一个简单的例子说明: 编译原理简单过程:词法分析 --> 语法分析 --> 语义分析和中间代码生成 --> 优化 --> 目标代码生成 Java程序从源文件创建到程序运行要经过两大步骤: 1.Java文件会由编译器编译成class文件(字节码文件),会经过编译原理简单过程的前三步: 2.字节码由java虚拟机解释运行,解释执行即为目标代码生成并执行.因为java程序既要编译的同时也要经过JVM的解释运行,所以说Java被称为半解释语言!

OC学习小结之ios运行过程详解

1)ios核心类 UIView 视图,屏幕上能看得见的东西都是视图,例如:按钮.文本标签.和表格等 UIViewController:内部默认有个视图(UIView),负责管理UIView的生命周期.装配数据到UIView上显示.处理其事件 ios采用MVC模式:model -view -controller 2)运行过程 ios运行原理 1.先执行main函数 2.main函数调用UIApplicationMain函数 创建一个UIApplication实例,这个是一个单例对象,一个ios程序

C/C++编译链接过程详解

有些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错误信息不能定位到某一行).或者对语言的一些部分不知道为什么要(或者不要)这样那样设计.了解本文之后,或许会有一些答案. 首先看看我们是如何写一个程序的.如果你在使用某种IDE(Visual Studio,Elicpse,Dev C++等),你可能不会发现程序是如何组织起来的(很多人因此而反对初学者使用IDE).因为使

React-Native工程项目打包编译发布过程详解

前言 现在大红大紫的React-Native框架热度可谓与日俱增,React-Native的热更新操作,在开发过程中的确带来很多好处,但是对于发布来讲,不同平台却不尽相同, 下面来具体看一下Android和IOS两个平台是如何执行发布产品的. React-Native之Android平台发布 Android平台有两种发布方式,一种是借助于命令行操作,另外一种是借助于Android Studio进行发布,具体步骤我们来看一下: 借助Android Studio发布版本 首先,借助于Android

Servlet运行过程详解

比如,在浏览器地址栏输入http://ip:port/web01/hello step1,浏览器依据ip,port建立与servlet容器(容器同时也是一个简单的web服务器)之间的连接. step2,浏览器将请求数据打包(按照http协议,该数据包也称为请求数据包). step3,浏览器发送请求数据包给容器. step4,容器收到请求数据包之后,解析该数据包,并将解析之后得到的数据封装到request对象上,同时,容器还要创建response对象. step5,容器要依据请求资源路径("/we

反编译过程详解

这段时间在学Android应用开发,在想既然是用Java开发的应该很好反编译从而得到源代码吧,google了一下,确实很简单,以下是我的实践过程. 在此郑重声明,贴出来的目的不是为了去破解人家的软件,完全是一种学习的态度,不过好像通过这种方式也可以去汉化一些外国软件. 一.反编译Apk得到Java源代码首先要下载两个工具:dex2jar和JD-GUI 前者是将apk中的classes.dex转化成Jar文件,而JD-GUI是一个反编译工具,可以直接查看Jar包的源代码. dex2jar和JD-G

ASP.NET 运行时详解 揭开请求过程神秘面纱

对于ASP.NET开发,排在前五的话题离不开请求生命周期.像什么Cache.身份认证.Role管理.Routing映射,微软到底在请求过程中干了哪些隐秘的事,现在是时候揭晓了.抛开乌云见晴天,接下来就一步步揭开请求管道神秘面纱. 上篇回顾 在介绍本篇内容之前,让我们先回顾下上一篇<ASP.NET运行时详解 集成模式和经典模式>的主要内容.在上一篇随笔中,我们提到ASP.NET运行时通过Application的InitInternal方法初始化运行管道.ASP.NET运行时提供了两种初始化管道模

uboot主Makefile分析(t配置和编译过程详解)

1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_config  跳转执行mkconfig用来配置并生成config.mk(board/samsung/x210目录下为指定链接地址的与主uboot目录的config.mk不同) autuconfig.mk 2.框图 3.uboot主Makefile分析 3.1.uboot version确定(Make

uboot配置和编译过程详解【转】

本文转载自:http://blog.csdn.net/czg13548930186/article/details/53434566 uboot主Makefile分析1 1.uboot version确定(Makefile的24-29行) Makefile代码部分: [plain] view plain copy VERSION = 1 PATCHLEVEL = 30 SUBLEVEL = 4 EXTRAVERSION = U_BOOT_VERSION = $(VERSION).$(PATCHL