预处理的那点事儿

来源:互联网 发布:淘宝网药假吗 编辑:程序博客网 时间:2024/05/16 12:14

编译一个C程序的第一个步骤就是对它进行预处理,在平常学习的时候,很多人认为预处理就是include和define两种。其实在预处理里,这两个只能算是常用的,下面将把ANSI标准定义的C语言预处理指令为大家罗列出来。
这里写图片描述

除了上面所说的外,还有以下的宏:
_ LINE_:表示正在编译的文件的行号;
_ FILE_:表示正在编译的文件的名字;
_ DATE_:表示编译时刻的日期字符串;
_ TIME_:表示编译时刻的时间字符串;
_ STDC_:判断该文件是不是定义标准C程序;

1.宏定义
<1>数值宏定义
在平时写代码的时候,我们经常会定义一些数值,例如PI的值为3.14,但在后续应用中可能需要提高精度,此时需要将所有在代码中出现的PI都改掉,这样的工作量非常大。一般来说,我们会在代码的最前端写上:#define PI 3.14 这样子在需要用3.14的时候都写得是PI,需要改动的时候只需要改动这个宏定义。
注意:编译器在编译的时候,会将代码中所有的PI都换成我们定义的具体数值。

<2>表达式宏定义
当然,除了可以宏可以定义数值,表达式这种也是可以的。
例如:表示一年有多少秒 #define SUM 60* 60* 24* 365
那么如果定义的是一个宏函数呢?
比如求一个数x的平方。就可以写成:#define SUM(x) x*x
当x=10 ,编译的时候就是10 * 10。可当表达式比较复杂,我们写出的可能是(10+x) *(10+x),我们想表达的是(10+x)这个数的平方,可编译器执行时,它会这样理解:10+x *10+x ,这个就和我们期望的有点差距了,所以当我们要用宏去定义函数表达式之类的时候,一定要注意表达式的优先级!

<3>.#undef
#undef是用来取消宏定义的,用法如下:
#define PI 3.1415925
……
#undef
在#undef后的PI,值就不在是3.1415925了。

2.条件编译
在预处理里很重要的一类就是条件编译,条件编译的意思就是说在某种情况下,我们需要执行第一段程序,当在另一种情况下时,需要执行另一段。最常见的应该是我们用的一些软件包,当操作位数是32位时,是怎样,换成64位又怎样。下面就说条件编译的三种形式:
<1>
#ifdef 标识符
…A…
#else
…B…
#endif

如果标识符已被#define定义,则对A进行编译,否则对B进行编译。如果没有else,可直接省略这段。变成:
#ifdef 标识符
…A…
#endif

<2>
#ifndef 标识符
…A…
#else
…B…
#endif

如果标识符没有被#define定义,则对A进行编译,否则对B进行编译。

<3>
#if 常量表达式
…A…
#else
…B…
#endif

如果常量表达式为真,则对A进行编译,否则对B进行编译。所以这种形式可以让程序在不同的条件下完成不同的功能。

3.文件包含
文件包含是预处理的一个重要功能,它可以把多个源文件进行编译,生成一个目标文件。每次在我们写代码的时候,首先会引用头文件,这就是一个最常见的文件包含。

#include<文件名>和#include”文件名”到底有什么差异?

用尖括号括起来的表示预处理需要带系统规定的路径下去获得这个文件。
双引号表示预处理先去当前路径下去查找这个文件,如果查找不到再去查找系统指定的路径信息。

4.#pragma
关于pragma的用法我们用的最多的是:#pragma once
#pragma once
只要在头文件中最开始接入这条指令就可以避免头文件被多次编译。

5.函数与宏的不同之处
之前在前面说了如何定义一个宏函数,很多人就宏和函数傻傻分不清楚了。接下来,用一个表格展现一下:

属性 宏 函数 代码长度 每次使用时,宏代码将被替换到程序中。除了非常小的宏之外,其他的长度都会大幅度增长。 代码只出现在一个地方,每次调用函数时,只是跳到这个部分在执行一遍。 执行速度 更快 存在压栈的额外开销 参数求值 参数每次用于宏定义都需要重新求值,具有副作用的宏参数可能会导致不可预料的结果。 参数被调用时会求值一次,在函数中使用参数不会造成其他特殊问题。 参数类型 宏和类型无关,只要对参数的操作是合法的,可用于各种类型 和类型有关,类型不同就需要使用不同的函数。

6.预处理
当一个程序写好后,第一步是进行预处理。预处理的目的是:宏定义的具体化;去掉注释;展开头文件;条件编译。预处理完成生成的是“.i”文件,当这一步进行完后,开始进行编译。编译主要是将C语言转换成汇编语言,当这个工作完成后,生成“.s”文件。接下里进行的是汇编阶段,这个阶段的主要工作是将汇编语言变成二进制,生成“.o”文件。最后进入链接阶段,完成“合并段表”和“符号表的合并及符号的重定义”。每个阶段都有自己的任务,共同配合完成整个预处理的过程。

0 0
原创粉丝点击