`
美丽的小岛
  • 浏览: 310539 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

C & C++的编译

    博客分类:
  • c
  • c++
 
阅读更多
C/C++编译过程

C/C++编译过程主要分为4个过程
1) 编译预处理
2) 编译、优化阶段
3) 汇编过程
4) 链接程序

一、编译预处理

(1)宏定义指令,如#define Name TokenString,#undef等。 对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,

但作为字符串常量的 Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。

(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。

预编译程序将根据有关的文件,将那些不必要的代码过滤掉

(3) 头文件包含指令,如#include "FileName"或者#include <FileName>等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),

同时包含有各种外部符号的声明。 包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。

在程序中#include它们要使用尖括号(< >)。

另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。

(4)特殊符号,预编译程序可以识别一些特殊的符号。 例如在源程序中出现的#line标识将被解释为当前行号(十进制数),
上面程序实现了对宏line的运用

(5)预处理模块 预处理工作由#pragma命令完成,#Pragma命令将设定编译器的状态或者是指示编译器完成一些特定的动作。

#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。

依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
打开C标准库函数,如stdio.h,我们总能找到下面这一句指示编译器初始化堆栈
#include "iostream"
#line 100
using namespace std;
int main(int argc, char* argv[])
{
cout<<"__LINE__:"<<__LINE__<<endl;
return 0;
}
/*--------------------
* 输出结果为:
* __LINE__:103
* 本来输出的结果应该是 7,但是用#line指定行号之后,使下一行的行号变为,
* 到输出语句恰为行103
---------------------*/
C/C++编译过程
或者程序指示编译器去链接系统动态链接库或用户自定义链接库
二、编译、优化阶段
经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。
在《编译原理》中我们可以了解到一个编译器对程序代码的编译主要分为下面几个过程:
a) 词法分析
b) 语法分析
c) 语义分析
d) 中间代码生成
e) 代码优化
f) 代码生成
g) 符号表管理
h) 将多个步骤组合成趟
i) 编译器构造工具
在这里我们主要强调对函数压栈方式(函数调用约定)的编译处理
C与C++语言调用方式大体相同,下面是几种常用的调用方式:

__cdecl 是C DECLaration的缩写(declaration,声明),表示C语言默认的函数调用方法:所有参数从右到左依次入栈,

这些参数由调用者清除,称为手动清栈。被调用函数不需要求调用者传递多少参数,调用者传递过多或者过少的参数,

甚至完全不同的参数都不会产生编译阶段的错误。

_stdcall 是StandardCall的缩写,是C++的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,

最后一个入栈的是this指针。这些堆栈中的参数由被调用的函数在返回后清除,使用的指令是 retnX,X表示参数占用的字节数,

CPU在ret之后自动弹出X个字节的堆栈空间。称为自动清栈。函数在编译的时候就必须确定参数个数,

并且调用者必须严格的控制参数的生成,不能多,不能少,否则返回后会出错。

PASCAL 是Pascal语言的函数调用方式,在早期的c/c++语言中使用这种调用方式,

参数压栈顺序与前两者相反,但现在我们在程序中见到的都是它的演化版本,其实
#pragma comment(lib,_T("GDI32.lib"))
#ifdef _MSC_VER
/*
* Currently, all MS C compilers for Win32 platforms default to 8 byte
* alignment.
*/
#pragma pack(push,_CRT_PACKING)
#endif /* _MSC_VER */
C/C++编译过程
质是另一种调用方式
_fastcall是编译器指定的快速调用方式。由于大多数的函数参数个数很少,使用堆栈传递比较费时。因此_fastcall通常规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递。不同编译器编译的程序规定的寄存器不同。返回方式和_stdcall相当。
_thiscall 是为了解决类成员调用中this指针传递而规定的。_thiscall要求把this指针放在特定寄存器中,该寄存器由编译器决定。VC使用ecx,Borland的C++编译器使用eax。返回方式和_stdcall相当。
_fastcall 和 _thiscall涉及的寄存器由编译器决定,因此不能用作跨编译器的接口。所以Windows上的COM对象接口都定义为_stdcall调用方式。
C中不加说明默认函数为_cdecl方式(C中也只能用这种方式),C++也一样,但是默认的调用方式可以在IDE环境中设置。简单的我们可以从printf函数看出
printf使用从从左至右压栈,返回int型并由_CRTIMP指定封在动态链接库中。
通过金典的hello world程序我们可以知道编译器对其argc和argv[]这两个参数进行了压栈,并且argc留在了栈顶
优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化处理主要分为下面几个过程:
1) 局部优化
a) 基本块的划分
b) 基本块的变换
c) 基本块的DAG表示
d) DAG的应用
e) 构造算法讨论
2) 控制流分析和循环优化
a) 程序流图与循环
/*金典的hello world*/
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("hello world");
return 0;
}
_Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);
#define CALLBACK _stdcall /* Windows程序回调函数*/
#define WINAPI _stdcall
#define WINAPIV _cdecl
#define PASCAL _stdcall /*在c++语言中使用了StandardCall调用方式*/
#define PASCAL _cdecl/*在c语言中使用了C DECLaration调用方式*/
C/C++编译过程
b) 循环
c) 循环的查找
d) 可归约流图
e) 循环优化
3) 数据流的分析与全局优化
a) 一些主要的概念
b) 数据流方程的一般形式
c) 到达一定值数据流方程
d) 可用表达式及其数据流方程
e) 活跃变量数据流方程
f) 复写传播
经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,方可能被机器执行。

三、汇编过程 

汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,

都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。

目标文件由段组成。通常一个目标文件中至少有两个段: 代码段:该段中所包含的主要是程序的指令。

该段一般是可读和可执行的,但一般却不可写。 数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

四、链接程序

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);

在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,

使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。

根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:

(1)静态链接 在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。

这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,

其中的每个文件含有库中的一个或者一组相关函数的代码。 

(2) 动态链接
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。
链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量
的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应
进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
C/C++编译过程
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动
态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一
些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一

定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。

-----------------------------------------------------------------------------------------------------------------------------------作者  张彦升

 转:http://blog.csdn.net/microzone/article/details/6707327

分享到:
评论

相关推荐

    C语言&C++.zip

    压缩包中的 "c--c-master" 文件很可能是一个C和C++的学习项目或者代码库,可能包含了示例代码、练习题或教程。这些资源可以帮助学习者从实践中理解C语言和C++的基础概念,逐步掌握编程技能。通过阅读和实践这些代码...

    ObjectiveC&C++的混合编译简单demo

    ObjectiveC是Apple的面向对象的编程语言,基于C语言,而C++则是一种广泛使用的通用、面向对象的编程语言,拥有丰富的库支持和高效性能。这两种语言可以混合使用,以利用各自的优点,比如ObjectiveC的Objective-C ...

    高级C C++编译技术_[美]斯特瓦诺维奇著

    《高级C/C++编译技术》一书由[美]斯特瓦诺维奇撰写,是一部深入探讨C和C++编译技术的专业著作。本书的核心内容涵盖了C/C++编程语言的底层细节,尤其是关于编译器的工作原理、库的加载机制以及程序打包技术等方面的...

    Turbo C & C++ for Windows 集成实验与学习环境

    《Turbo C & C++ for Windows 集成实验与学习环境》是一款专为Windows操作系统设计的C语言和C++编程学习平台,尤其适合初学者入门。这款软件提供了丰富的功能,帮助用户在学习C和C++的过程中进行实践操作,提高编程...

    c&&c++嵌入式编程

    3. 高效性能:C语言编译后的代码运行速度快,内存占用小,适合资源有限的嵌入式环境。 二、C++在嵌入式编程中的优势 1. 类和对象:C++引入了面向对象编程,通过类和对象封装数据和行为,提高了代码的可维护性和复用...

    C,C++编译环境搭建

    ### C/C++编译环境搭建详解 在计算机编程领域,C和C++是两种非常重要的编程语言,广泛应用于操作系统、游戏开发、系统级编程、嵌入式系统等多个领域。搭建一个稳定高效的C/C++编译环境是每个程序员的必修课,尤其是...

    C/C++编译技术

    本上传pdf文件主要讲解C/C++编译技术,适合入门者阅读。

    C&&C++------面试大全.rar

    "C&&C++------面试大全.rar"这个压缩包文件,显然是一份针对C++和C语言面试的综合资料,涵盖了这两个语言的关键知识点和常见面试问题。 首先,C语言作为C++的基础,它的主要知识点包括: 1. **基本语法**:变量、...

    C++编译原理 等等总结

    本文将围绕“C++编译原理”、“C++类对象内存结构”、“面向对象的编程总结”以及“C++语言参考”这四个主题进行深入探讨。 首先,我们来了解一下“C++编译原理”。编译器是将高级语言(如C++)翻译成机器语言的...

    反编译工具(DLL 转c/c++ 工具)

    标题中的“反编译工具(DLL 转 c/c++ 工具)”是指一类能够将动态链接库(DLL)文件转换为C或C++源代码的软件工具。DLL是Windows操作系统中的一种共享库,它包含可由多个程序同时使用的函数和资源。这种转换过程在...

    C语言调用C++类中的方法

    总之,C语言调用C++类的方法涉及到C++的extern "C"声明、函数指针的使用以及正确的编译和链接步骤。理解这些细节对于进行跨语言编程至关重要。通过实践和调试,你可以更熟练地掌握这一技巧,从而在实际项目中灵活...

    vector(容器)、 c &c++编程规范doc、495个c问题.pdf、c常见问题.pdf

    这与C语言中的静态数组形成鲜明对比,后者在编译时就必须确定大小,且无法动态扩展。`vector`的常用操作包括插入、删除、访问元素以及遍历。例如,你可以通过索引访问元素,如`vector&lt;int&gt; v; v[0] = 10;`,也可以...

    Dev-C++ 编译多文件程序的方法&安装使用教程

    5. 现在,我们可以使用 Dev-C++ 来编写、编译、运行、调试 C/C++ 程序了。 需要注意的是,.c 代表 C 程序,.cpp 代表 C++ 程序。 多文件程序编译 在 Dev-C++ 中,我们可以使用项目文件来管理多文件程序。以下是...

    各种C++预编译命令

    预编译命令是C语言和C++语言中非常重要的一部分,它们可以在编译前对代码进行处理和修改,从而影响编译器的行为。本文将详细介绍各种C++预编译命令,包括#pragma指令的多种用法。 #pragma指令 #pragma指令是C语言...

    paho-mqtt-c & c++ windows库, 包含所有lib dll .h 及测试exe文件

    2. **编译源码**:如果压缩包中包含源代码,需要使用VS编译器编译Paho MQTT-C和C++库,生成对应的.lib或.dll文件。 3. **链接库文件**:在项目的链接器设置中,将生成的库文件路径添加到库目录,以便编译时能正确...

    Makefile万能通用版(C++和C混合编译也适用)

    Makefile万能通用版(C++和C混合编译) Makefile是一种通用的自动编译工具,可以自动编译C和C++源代码,生成可执行文件。本Makefile万能通用版支持C和C++混合编译,能够满足大多数编译需求。 Makefile的基本结构 ...

    C++开发语言源代码反编译工具

    C++开发语言源代码反编译工具

Global site tag (gtag.js) - Google Analytics