预处理器简介

预处理器

       预处理是C编译器做的第一件事情,主要是做一些文本方面的工作。包括:删除注释、插入被#include包含的文件、定义和替换由#define指令定义的符号以及代码的部份内容,和条件编译。

预定义符号

       预定义符号如下表所示:

__FILE__

进行编译的文件名

__LINE__

文件的当前行号

__DATE__

文件编译的日期

__TIME__

文件编译的时间

__FUNCTION__

函数名

__STDC__

如果遵循ANSI C,它被定义

       预定义符号都是双下划线,通常用到最多的是前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_SIZE100LITTLE_ENDIAN没有指定值,那么默认为0.

       命令行也可以取消定义,用-U。方法就不叙述了。(注意:gcccl都是区分大小写的)

条件编译

       具体地讲,条件编译就是几个条件指令:#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语言的宏中是容许嵌套的,编译器展开宏后,会在运行以便于处理器,如果有宏,则继续,当然,如果出现递归时则会停止。一般的展开规律像函数的参数一样,先展开参数,在分析函数,所以展开顺序是由内而外,但是当宏中有#则不再展开参数了,如果宏中有##,则先展开函数,再展开里面的参数。

你可能感兴趣的:(预处理器简介)