您的位置:首页 > 其它

C陷阱篇之define的缺陷

2013-12-15 19:13 204 查看
#define存在一些先天不足。在以下情形下要格外小心:

避免宏参数中的++与--操作。

带参数的宏定义形式上与函数很接近,程序员调用时有时会把它们视为等价。但实际define定义的伪函数相比真正函数有一些使用限制,比如:

#define max(A,B)((A)>(B)?(A):(B)) //看上去是想得到两个数中较大的

void main()

{

int i=1, j=2, x;

x = max(i++, j++);

printf("x = %d\n", x);

printf("i = %d\n", i);

printf("j = %d\n", j);

}

输出结果:x = 3 i = 2 j = 4。为什么不是x = 2, i = 2, j = 3? 因为预处理器对宏做文本替换后变成:x
= ((i++) > (j++) ? (i++) : (j++)),其中j将被计算两次。因此用宏定义时,一定要小心操作数中的++ --,如果max是真正的函数,处理这种带++
--的参数没问题,但#define定义的伪函数却不行。

C库中的大小写转换函数toupper()也是一个典型例子,为减少函数调用开销,很多C库里toupper用宏实现:#define
toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) + ('A' - 'a') : (c))。它确实比函数调用快,但一旦遇到toupper(*p++)这种调用方式,也会出现奇怪结果。

宏定义的括号漏洞

#define add(A,B) A+B

x = add(1,2) * 10;

结果x=21。为什么不是30?仔细看:add宏展开后表达式变成x
= 1+2*10,定义里没用括号保护,展开后与预期功能不符,这种问题非常常见,再比如:

#define BLK_LEN 32 * 1024

block_num = bufsize / BLK_LEN;

替换后:block_num = stat_buf.st_size/32*1024;。所以宏定义里要多用括号,避免干扰。

不要用define代替typedef

#define pin (int*)

pin a,b;

本意a和b都定义为int指针,但替换后变成int* a,b;即a是int指针,而b是int变量。所以对这种类型重定义,应该用typedef,而不是不伦不类的define。

define多行定义续行符后不能有空格

define可定义多行代码,但续行符后不能有空格,否则会产生很多编译错误

#define MACRO(arg1, arg2) do { \

stmt1; \

/* ... */ \

} while(0) /* (no trailing ; ) */

这个定义有问题么?是的,只是每行结尾的空格在代码编辑器中一般看不到。一旦写完换行符’\’后大拇指习惯性一按,一个“隐形”错误就产生了。如果总提示多行define定义有错,又找不到问题时,先把换行符\后的空格清理一下。

此外,define语句后不能随便加;号:

#define MIN(A,B) ((A) <= (B) ? (A) : (B));

仔细看,行尾多了;号,#define不是C语句,不能随便加;号,否则替换时;号也会跟着。

总结:

define仅仅是代码替换,有时形似“函数定义”但不是真正的函数定义。另外define还会使调试不方便,所以建议用const量和inline函数替换#define。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: