C 基础 - 预处理器与C库

 

翻译程序的第一步:

首先:编译器把源代码中出现的字符映射到源字符集。

第二:编译器定位每个 \ 后面跟着换行符实例,并删除它们。

第三:编译器把文本划分成处理记号序列、空白序列和注释序列。

最后:准备进入预处理阶段,查找#号开始的预处理指令。

 

在编译时打开编译的 -p 选项,可以看到预处理器的输出。

 

预处理指令类型:

* 宏定义

* 文件包含

* 条件编译 

 

#define 明示常量

#define 标识符 替换列表

 

C预处理器在程序执行之前查看程序。

预处理器不做计算,不对表达式求值,只进行替换。

  

类对象宏

#define (符号常量), 定义时组成部分如下:

* #deinfine 符号指令

* 宏

* 替换列表

对于大部分的数字常量,可以使用符号常量。

 

类函数宏

#define 标识符(x1, x2, ... xn)   替换列表

 

#define 中还可以使用参数

#define SQUARE(X) X*X

z = SQUARE(2);

 

练习: 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

 

 

练习: 写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。

#define MIN(A,B) ( (A) <= (B) ? (A) : (B) ) 

 

 

练习:

有如下带参数宏定义

#define TAILQ_HEAD(name, type)                        \
struct name {                                \
    struct type *tqh_first;    /* first element */            \
    struct type **tqh_last;    /* addr of last next element */        \
}

 

 

有如下声明

TAILQ_HEAD(, tailq_entry) my_tailq_head;

 

 

宏展开后结构

struct { 
  struct tailq_entry *tqh_first; 
  struct tailq_entry **tqh_last; 
} my_tailq_head;

 

 

在编译时,使用 -E 选项来编译,查看

gcc -O2 -o tailq_ex tailq_ex.c -E

 

 

文件包含: #include 指令

当预处理器发现#include指令时,会查看后面的文件名把文件的内容包含到当前文件中。

 

const与#define 相比,有何优点?

1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。

 

posted @ 2017-09-10 18:49  elewei  阅读(281)  评论(0编辑  收藏  举报