标题:宏定义


1,定义一个宏,计算数组的长度
#define ARRAYSIZE(a) sizeof(a)/sizeof(a[0])

2,定义一个宏,计算结构体中成员的偏移
#define offsetof(s,m) (size_t)&(((s *)0)->m) 

3,多语句宏:
在程序设计中,另外一个很经典的算法就是将两个数进行交换。比如有2个整数:
int a = 10;
int b = 20;
交换后,a的值为20,b的值为10。在程序里面,必须要使用一个临时变量,来先把a的值保存起来,然后再把b的值赋给a,再把临时变量保存起来的a的值赋值给b。如果不用临时变量把a的值保存起来,那么当把b的值赋给a的时候,a的值就会丢失。 错误的写法如下:
a = b; //a的值丢失
b = a;//a和b的值最终都是b的值
正确的写法:
int tmp = a; //使用tmp变量保存a的值
a = b;
b = tmp;
上面的算法可以用宏来定义如下:
#define SWAP(a,b)
{ \
    int tmp; \
    tmp = a; \
    a= b; \
    b = tmp; \
}
上面的宏定义中,每行语句都用一个’\’来连接,用来将两个int类型的整数交换。然后在程序中使用这个宏定义如下:
void main(void)
{
    int a = 10;
    int b = 20;
    SWAP(a, b);
    printf(“a=%d, b=%d\n”, a, b);
}
这种对于多条语句的定义方法,虽然在普通的时候一般不会出现什么问题。但是,来看看下面的条件语句:
If (x>y)
    SWAP(a, b);
else
    SWAP(a,b);
如果对上面的条件语句进行宏展开,就得到了下面的程序:
if (x>y)
{
    int tmp;
    tmp = a;
    a= b;
    b = tmp;
};
else
{
    int tmp;
    tmp = a;
    a= b;
    b = tmp;
};
很显然,else语句部分会和if语句被;语句分割,所以会出现一个语法错误。即else语句会找不到if语句与之配对了。
于是,多余多条语句定义的宏,一般采用do-while(0)的格式来定义:
#define SWAP(a,b)
do { \
    int tmp; \
    tmp = a; \
    a= b; \
    b = tmp; \
}while(0)
这样,上面的程序展开之后:
if (x>y)
do{
    int tmp;
    tmp = a;
    a= b;
    b = tmp;
}while(0);
else
do {
    int tmp;
    tmp = a;
    a= b;
    b = tmp;
}while(0);
这样宏定义中的语句也只执行一次就退出了do-while循环,也避免了上面宏定义出现的一个特殊错误。

4,宏就是简单替换。记住这是简单的替换而已,不要在中间计算结果,一定要替换出表达式之后再算。
比如#define MAX(a,b) ((a)>(b)?(a):(b))
则遇到MAX(1+2,value)则会把它替换成:
((1+2)>(value)?(1+2):(value))

5,对于宏的二义性,来看看下面的例子。从下列选项中选择不会引起二义性的宏定义是:
A、 #define POWER(x) x*x
B、 #define POWER(x) (x)*(x)
C、 #define POWER(x) (x*x)
D、 #define POWER(x) ((x)*(x))
分析:
A.#define POWER(x) x*x
如果调用POWER(5+6),本意是 (5+6)*(5+6)=121,实际却是:5+6*5+6=41
B.#define POWER(x) (x)*(x)
如果调用POWER(5+6)/POWER(5+6),本意是得到结果为1,实际却是:(5+6)*(5+6)/(5+6)*(5+6)=11*11/11*11=121
C.#define POWER(x)(x*x)
如果调用POWER(5+6)+POWER(5+6),本意是 (11*11)+(11*11)=121+121=242,实际却是: (5+6*5+6)+(5+6*5+6)=41+41=82
D.没有二义性。


看文字不过瘾?点击我,进入周哥教IT视频教学
麦洛科菲长期致力于IT安全技术的推广与普及,我们更专业!我们的学员已经广泛就职于BAT360等各大IT互联网公司。详情请参考我们的 业界反馈 《周哥教IT.C语言深学活用》视频

我们的微信公众号,敬请关注