现在的位置: 首页 > 综合 > 正文

预处理学习笔记

2013年07月26日 ⁄ 综合 ⁄ 共 2111字 ⁄ 字号 评论关闭
预处理

宏定义:
#define N 20
#define STR "hello,world"

#define MAX(a,b) ((a)>(b)?(a):(b))

//两种预处理方式
gcc -E main.c
cpp main.c

1 函数式宏定义和真正的函数调用的不同:
1)宏定义的参数没有类型,预处理之负责做形式上的替换,而不做参数类型的检查
2)调用真正函数的代码和调用宏定义的代码编译生成的指令不同。
3) 宏定义的括号不可以省略
4)调用函数时先求实参表达式的值再传给形参。例如MAX(++a,++b),如果MAX是函数,则a和b只增加一次
如果MAX是定义的宏 MAX(++a,++b)=((++a)>(++b)?(++a):(++b))

如果需要重新定义一个宏,和原来的定义不同,可以现用#undef取消原来的定义,再重新定义,例如:
#define X 3
#undef X
#define X 2

2 内联函数
inline关键字告诉编译器,这个函数的调用要尽可能快,可以当普通的函数调用实现,也可以用宏展开的办法实现。

3 #、##运算符和可变参数
在函数式宏定义中,#运算符用于创建字符串,#后面应该跟一个形参。
#define STR(s) # s
STR(hello       world)

用cpp 命令预处理之后是"hello world",自动用"号把实参括起来成为一个字符串,并且实参中的连续多个空白字符被替换成一个空格。

在宏定义中可以用##运算符把前后两个预处理Token连接成一个预处理Token,和#运算符不同,##运算符不仅限于函数式宏定义,变量式宏定义也可以用。
#define CONCAT(a, b) a##b
CONCAT(con, cat)

预处理之后是concat

#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);

预处理之后变成:
    printf("The first, second, and third items.");
    ((x>y)?printf("x>y"): printf("x is %d but y is %d", x, y));

在宏定义中,可变参数的部分用__VA_ARGS__表示,实参中对应... 的几个参数可以看成一个参数替换到宏定义中__VA_ARGS__所在的地方。

4 宏展开的步骤
#define sh(x) printf("n" #x "=%d, or %d\n",n##x,alt[x])
#define sub_z 26
sh(sub_z)

sh(sub_z) 要用sh(x) 这个宏定义来展开,形参x对应的实参是sub_z ,替换过程如下:
  1. #x要替换成"sub_z"。
  2. n##x 要替换成nsub_z。
  3. 除了带#和##运算符的参数之外,其它参数在替换之前要对实参本身做充分的展开,所以
     应该先把sub_z 展开成26再替换到alt[x]中x的位置。
  4. 现在展开成了printf("n" "sub_z" "=%d, or %d\n",nsub_z,alt[26]),所有参数都替换完
     了,这时编译器会再扫描一遍,再找出可以展开的宏定义来展开,假设nsub_z或alt 是变
     量式宏定义,这时会进一步展开。

      #define x 3
      #define f(a) f(x * (a))
      #undef x
      #define x 2
      #define g f
      #define t(a) a
      t(t(g)(0) + t)(1);
展开的步骤是:
 1. 先把g展开成f再替换到#define t(a) a中,得到t(f(0) + t)(1);。
 2. 根据#define f(a) f(x * (a)) ,得到t(f(x * (0)) + t)(1);。
 3. 把x替换成2,得到t(f(2 * (0)) + t)(1);。注意,一开始定义x为3,但是后来用#undef
    x取消了x的定义,又重新定义x为2。当处理到t(t(g)(0) + t)(1);这一行代码时x已经定
    义成2了,所以用2来替换。还要注意一点,现在得到的t(f(2 * (0)) + t)(1);中仍然
   有f,但不能再次根据#define f(a) f(x * (a)) 展开了,f(2 * (0)) 就是由展开f(0) 得到
   的,这里面再遇到f就不展开了,这样规定可以避免无穷展开(类似于无穷递归),因此
   我们可以放心地使用递归定义,例如#define a a[0] ,#define a a.member 等。
4. 根据#define t(a) a,最终展开成f(2 * (0)) + t(1); 。这时不能再展开t(1) 了,因为这

   里的t就是由展开t(f(2 * (0)) + t)得到的,所以不能再展开了。

 5 条件预处理指示
#ifndef HEADER_FILENAME
#define HEADER_FILENAME
/* body of header */
#endif

 

抱歉!评论已关闭.