预处理器预处理是C编译器做的第一件事情,主要是做一些文本方面的工作。包括:删除注释、插入被#include包含的文件、定义和替换由#define指令定义的符号以及代码的部份内容,和条件编译。 预定义符号 预定义符号如下表所示:
预定义符号都是双下划线,通常用到最多的是前2个,用于打印log. #define 此指令应该是最为常见的,它的一般描述是 #define name stuff stuff是可选的。stuff不仅可以是常量,任何文本都可以用于替换。 #define name(parameter-list) stuff 上面这种形式被称为宏macro,它作为函数的替换的方式之一被广泛采用。不过C++中不太推荐这种方法,转而使用模板。不过,宏函数还是有很特殊的地方,且模版亦不能代替。比如字符串代替。 #define PRINT(FORMAT, VALUE) \ printf("The value is "FORMAT" ", VALUE) 在宏参数两边加上引号,表示以字符串形式替换。例如,下面的语句: PRINT("%d", x+10); 经过预编译后变为 printf("The value is %d", x+10); 这种转换只有当宏参数是字符串常量时,才可以被处理。如果在stuff里宏参数前加上'#',则对任意文本都有效。比如下面 #define PRINT(FORMAT, VALUE) \ printf("The value is "#VALUE" = "FORMAT" ", VALUE) 那么上面那条语句会编译为 printf("The value is x+10 = %d", x+10); 这样大提高了宏参数的灵活性。甚至,预处理器还有连接功能'##'(后面介绍)。 #define ADD(N, VALUE) hd##N += VALUE … ADD(a, 3); ó had += 3; 在许多的高级程序中,这类“奇技淫巧”被广泛使用。一方面,宏替换比函数往往能获得更高的效率;更重要的是,这类字符串处理是C/C++这种非脚本语言无法实现的。 #undef 通常是重定义一个宏。因为如果一个宏已经定义了,那么必须先取消定义,才能重新定义。 命令行定义 命令行定义就是通过编译器来定义。各种编译器都提供了一个选项来定义宏。以gcc为例: gcc -DMAX_SIZE=100 -DLITTLE_ENDIAN 这里定义了两个,MAX_SIZE为100,LITTLE_ENDIAN没有指定值,那么默认为0. 命令行也可以取消定义,用-U。方法就不叙述了。(注意:gcc和cl都是区分大小写的) 条件编译 具体地讲,条件编译就是几个条件指令:#if, #ifdef, #elseif, #else, #endif, #ifundef, defined。比如,判断一个宏是否定义,有三种方式: 1. #if MACRO_ 2. #ifdef MACRO_ 3. #if defined(MACRO_) 一般情况下,用前两个就可以了。但是后一个也非常有用,比如要判断多个条件组合时 #if defined(!MACRO1 || MACRO2 && MACRO3 ) 用其它方式会很麻烦。 其它指令 #error text-to-print 让编译器输出信息对开发者来说,比注释更有效。 #和## 在C语言的宏中是容许嵌套的,编译器展开宏后,会在运行以便于处理器,如果有宏,则继续,当然,如果出现递归时则会停止。一般的展开规律像函数的参数一样,先展开参数,在分析函数,所以展开顺序是由内而外,但是当宏中有#则不再展开参数了,如果宏中有##,则先展开函数,再展开里面的参数。 |