网站地图

【附】C语言预处理机制学习笔记

创建时间:2013-11-05 23:05:19最后修改:2013-11-05 23:05:19

一、变量式宏定义(Oject-like Macro)

宏只是进行简单的字符串替换:
    #define N 20
    #define STR "hello, world\n"

 二、函数式宏定义(Function-like Macro)

宏可以类似函数一样使用:
    #define MAX(a, b) ((a)>(b)?(a):(b))

下面是他的几个特点特点:以下是几个应用举例:
#define sdram_selfrefresh_disable(saved_lpr0) \
    do
    { \
        at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
        at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
    }
    while (0)
这里的宏用do---while括起来就是为了让这个宏替换的代码总是当作一个整体看待。

三、内联函数(inline function)

内联函数是为了减少因函数调用产生的开销,会在调用函数时进行代码展开,而不是函数调用的方式,弊端是会导致编译文件变大:
    static inline int rwsem_is_locked(struct rw_semaphore *sem) { return sem->count != 0; }

四、#和##运算符和可变参数

#和##是预处理运算符,在函数式宏定义中,#运算符后面应该跟一个形参,之间用空格或Tab分割,用于创建字符串字面值:
#define STR(s) # s STR(hello world)
调用STR宏产生字符串字面值“hello world”。

在宏定义中##运算符把前后两个预处理Token连接成一个预处理Token,并且变量式宏定义中也可以用##运算符:
    #define CONCAT(a, b) a##b
    CONCAT(con, cat)

预处理之后是concat,比如定义一个宏展开为两个#符号:
    #define HASH_HASH # ## #
 注:中间空格不能少,因为####根据最长匹配原则是看作两个##,报错,因为预处理Token不能出现在开头或末尾。

函数式宏定义也有可变参数:
    #define showlist(...) printf(#__VA_ARGS__)
    #define report(test,...) ((test)?printf(#test):\
    printf(__VA_ARGS__))
    showlist(The first ,second, and third items.);
    report(x>y, "x is %d but y is %d",x,y);

预处理展开,宏定义中可变参数部分用__VA_ARGS__表示:
    printf("The first ,second, and third items.");
    ((x>y)?printf("x>y"):printf("x is %d but y is %d",x,y));

当__VA_ARGS__是空参数时,##运算符会把前面的逗号吃掉。

注:真正的宏应该学习Common Lisp的宏,体会宏的强大!

五、#undef预处理指示

如果用#define重复定义宏,规定这些宏定义必须一模一样,否则报错。

如果用#undef取消宏定义,取消一个没有定义的宏不会报错。

六、宏展开的步骤。

举例:
#define sh(x)
printf("n" #x "=%d, or %d\n",n##x,alt[x])
#define sub_z 26 sh(sub_z)

展开过程:
1、x的实参是sub_z
2、#x替换为sub_z
3、n##x替换为nsub_z
4、sh(x)展开为:printf("n sub_z =%d, or %d\n",nsub_z,alt[sub_z]);
5、其实sub_z最先替换为26
6、第4步的展开真实是:printf("n 26 =%d, or %d\n",n26,alt[26]);

七、条件预处理指示

实例1:
#ifndef HEADER_FILENAME
#define HEADER_FILENAME
/*body of header*/
#endif

实例2:
#if MACHINE == 68000 int x;
#elif MACHINE == 8086 long x;
#else #error UNKOWN TARGET MACHINE #endif

实例3:
#ifdef HEADER_FILENAME
#define HEADER_FILENAME
#undef HEADER_FILENUM
/*body of header*/
#endif

实例4:
    #if defined x
等于
    #ifdef x

    #if !defined x
等于
    #ifndef x

实例5:
#if 0
....
#endif

八、其它预处理特性

<<上一篇:C语言预处理运算符详解 目录