宏只是进行简单的字符串替换:
#define N 20
#define STR "hello, world\n"
宏可以类似函数一样使用:
#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括起来就是为了让这个宏替换的代码总是当作一个整体看待。
内联函数是为了减少因函数调用产生的开销,会在调用函数时进行代码展开,而不是函数调用的方式,弊端是会导致编译文件变大:
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的宏,体会宏的强大!
如果用#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