您的位置:首页 > 其它

理解程序编译预处理与链接过程

2016-11-03 11:23 423 查看
首先熟悉一些预处理标识符

__FILE__  :进行编译的文件

__LINE__  :文件当前行号

__DATE__  :文件被编辑的周期

__TIME__  :文件被编辑的时间

# :使用预处理器将宏参数转换成一个字符串

##:将位于它两边的符号连接成一个符号。

示例 :

__FILE__  :用LINUX指令来观察它的预处理结果和最后输出的结果

#include<stdio.h>

int main()

{

     printf("file:%s\t,line:%d,date:%s,time:%d\n",__FILE__,__LINE__,__DATE__,__TIME__);

      return 0;

}

__LINE__ ,__DATE__  ,__TIME__也是同理,因此将它们一次写完观察预处理之后的结果即gcc -E  mytest.c -o mytest.i,也可以直接观察程序运行完之后的结果即gcc mytest.c 然后用./a.out观察程序运行完的结果



由以上结果可以看出程序在预处理之后就已经将__LINE__ ,__DATE__  ,__TIME__这些预处理标识符用 ”mytest.c",4,"Nov  3 2016 ","10:24:40"替换了即预处理之后的结果就等同于程序运行完之后的结果。

示例:

'#‘使用预处理器将宏参数转换成一个字符串代码如下:

#define M 10

#define PRINT(FORMAT,VALUE) printf("the value of" #VALUE"is" FORMAT"\n",VALUE);

#include<stdio.h>

int main()

{

    PRINT("%d",M);

    return 0;

}

预处理之后的结果:

 


由以上的结果就可以看出在预处理之后宏参数通过’#‘就已经转换成一个字符串,而程序运行完之后的结果也是宏参数M变成了一个字符串。

’##‘使用是将位于它两边的符号连接成一个符号

  


2、了解宏和函数

1、宏可以非常频繁地用于执行简单的运算,可以进行参数的替换

2、宏可以进行临近字符串的拼接并且可以替换掉其中的一部分

3、对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。

4、宏不可以出现递归

5、参数宏在定义时要多加小心,多加括号。

6、:函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换。在考虑效率的时候,可以考虑使用宏

7、在宏定义代码块时加上do
while(0)

和函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码拷贝将插入到程序中,除非宏非常短,否则使用宏可能会大幅度增大代码长度。但和函数相比有一些任务使用函数无法实现比如:

#define
MALLOC(n,type) ((type*)malloc((n)*sizeof(type)))

int
*pi=MALLOC(25,int);

这个宏的第二个参数是一种类型,它无法作为函数参数进行传递

这个宏替换完成之后:

int *pi=((int*)malloc((25)*sizeof(int)));

4 带副作⽤的宏参数

     当宏参数在宏定义中出现次数超过⼀次时,如果这个参数具有副作

⽤,那么当你使⽤这个宏时就可能出现危险,导致不可预料的结果。副作

⽤就是在表达式求值时出现的永久性效果。例如,下⾯表达式

   x + 1;

可以执⾏⼏百次,他每次获得结果都是⼀样的,这个表达式不具有副作

⽤。但是

  x ++;    

就有副作⽤:它增加x的值。当这个表达式下⼀次执⾏时,他将产⽣⼀个

不同的结果。MAX宏可以证明具有副作⽤的参数所引起的问题。

#define MAX( a, b )  ( (a) > ( b) ? (a ) : (b) )

        int x = 5;

        int y = 8;

        int z = MAX( x++, y++);

        printf("x = %d, y = %d, z = %d\n" , x, y, z );



可以用LINUX指令查看一下它的与处理结果



即它在进行选择时对y又进行了一次++

故y++执行了两次最后结果为10,其实比并不符合我们预期的结果故MAX宏可以证明具有副作⽤的参数所引起的问题。

3、理解编译链接整个过程和详细的每个过程

从C语言转换成机器能够识别的二进制需要如下几个过程

预处理(宏替换,去注释,头文件按照路径展开,条件编译)-->编译-->汇编-->链接

以这个程序为例

#define
MAX(a, b)  ((a) > (b) ? (a) : (b))

#include<stdio.h>

int main()

{

        int x = 5;

        int y = 8;

        int z = MAX(x++, y++);

        printf("x = %d, y = %d, z = %d\n", x, y, z);

        return 0;

}

~          

先来看预处理之后的结果:使用gcc
-E www.c -o ww.i 和vim.i指令



接下来进行编译使用gcc
-S www.i -o www.s 和vim.s指令



接下来在进行汇编使用gcc
-c www.s -o www.o 和vim www.o指令



最后是链接过程采用gcc
www.o -o www 和vim www指令

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: