c语言关于宏的使用十分频繁。可是宏的使用有利也有弊,与此同时,它仍是一个特别容易搞错的地方。正是基于此,它经常成为一些面试会侧重考察的地方。ios
所谓宏就是 #define 机制包括的一个规定,即容许把参数替换到文本中。它的声明方式:#define name(参数列表) stuff 面试
其中参数列表是一个由逗号分隔的符号列表,对应参数做用于stuff中,至关于宏替换函数;若是没有参数列表,那就是咱们日常用得比较多的宏替换变量了。安全
1. 分号问题函数
2. 符号优先级问题spa
3. 做用域问题调试
4.使用带反作用的宏参数code
宏定义处用了分号blog
#include <iostream>
using namespace std; #define MAX( l, r) l > r? l: r;
int main() { int a =1 , b=2; if( a) int max = MAX( a,b);// <=> max = a > b? a:b;; 出错!!
else { } return 0; }
符号优先级问题作用域
#include <iostream>
using namespace std; #define MAX( l, r) l > r? l: r
int main() { int a =1 , b=2; int max = MAX( a && 3, b);//a && 3 > b? a && 3: b 达不到预想结果
cout<<max; return 0; }
改造:io
#define MAX( l, r) ( (l)> (r)? (l) :(r) )
int main() { int a =1 , b=2; int max = MAX( a && 3, b);//(a && 3) > b? (a && 3) : b
cout<<max; return 0; }
做用域问题
#include <iostream> using namespace std; //=优先级很低,不用优先级问题 #define SWAP(l, r) {\ int tmp = l;\ l = r; \ r = tmp;} int main() { int a =1 , b=2; if(a) SWAP(a, b); //<=> {.... } ; 此处只容许出现一条语句,但这里产生2条 else { } cout<<a <<" "<<b<<endl; return 0; }
解决:用do{... }while(0) 解决
//=优先级很低,不用优先级问题 #define SWAP(l, r) do{\ int tmp = l;\ l = r; \ r = tmp;}while(0) int main() { int a =1 , b=2; if(a) SWAP(a, b); //<=> do{.... }while( 0) ; else { } cout<<a <<" "<<b<<endl; return 0; }
带反作用的宏参数
当宏参数在宏定义中出现次数超过一次时,若是这个参数具备反作用,那么当使用这个宏时就出现危险,致使不可预料的结果。反作用就是在表达式求值时出现永久性的效果。好比x++,它能够增长x的值。当下一次执行该表达式时,他将产生一个全新的结果。仍是之前面的的MAX函数为例
#include <iostream>
using namespace std; #define MAX(l, r) ( (l)>(r)? (l): (r)) int main() { int a =1 , b=2; int max = MAX(a++, b++); //<=> (a++)>( b++)? ( a++):( b++); //结果: 3 2 4
cout<<max<<" "<<a<<" "<<b<<endl; return 0; }
结果让较小的值a增长了一次,但确让较大的值b增长了2次。这种带反作用宏参数会修改变量的值,使用需格外注意。
优势:
1. 快! 因为是预处理时期直接宏替换,不用像函数那样来回调用返回,增长额外开销。
2. 因为能够替换变量,修改变量仅需在宏定义处修改,增长了程序的可维护性。
缺点:
1. 没有类型安全的检查。宏和类型是无关的,只要对参数操做合法,它可使用任何参数类型。
2. 极易出错。 宏参数求值是要依赖于周围表达式的上下文环境。没有合理地加括号,得不到指望的结果; 同时参数每次用于宏定义时,它们都会从新求值,因为这样屡次求值,因此让具备反作用的参数可能产生不可预料的结果。
3. 不可调试。因为预处理阶段,直接进行了宏替换,对替换掉的代码没法进行调试检查。
4. 替换插入代码,致使程序代码长度大大加长。