关于宏#define使用陷阱总结
2012-11-02 09:31
239 查看
宏定义发生在预编译阶段,简单的说本质就是文本替换。使用时,有以下注意事项:
1,用宏定义表达式时,要使用完备的括号
如一下三个例子:
#define ADD(a,b) a+b
#define ADD(a, b) (a + b)
#define ADD(a, b) (a) +(b)
这三种定义,全部都是不符合要求的。陷阱如下:
在计算ADD(a,b)*ADD(c,d)时,显然第一种出问题了。
#define MULTIPLE(a, b) (a*b) 在计算(a+b)*c时,调用MULTIPLE(a+b,c)得到的结果错误。
因此一定要使用完备的括号,如下示例:
#define ADD(a,b) ((a) + (b))
2,使用宏定义,不允许参数发生变化,这也就是带参数的宏定义和函数的区别:
如下测试源码:
最终的结果是a = 12; b = 11; r1 = 100; r2 = 100; 以上结果在vc6.0下获得。之所以a变成12,是因为在替换的时候,a++被执行了两次。要避免这种行为,就要使宏参数不发生变化。
如:a++; r1 = sqrt(a), 一切就ok了!
3,使用大括号将宏定义包含的多条表达式括起来。
如下示例:
结果打印a是正常的,但打印b却是未初始化的结果。因为简单的文本替换,不能保证多条表达式都放到for循环体内。(这里,如果单独初始化一个变量,没有for循环时没有问题的。)上述的宏定义应改为:
注意这个“\”号哦,表示下面的一行和当前行在预编译时被认为在同一行。
最后,再简单对比下#define和 typedef的区别,#define发生在预编译阶段, typedef发生在编译阶段,可参考http://topic.csdn.net/t/20030810/14/2129718.html。更多细节上的区别,稍后再谈。
不对之处,大家多指正。
1,用宏定义表达式时,要使用完备的括号
如一下三个例子:
#define ADD(a,b) a+b
#define ADD(a, b) (a + b)
#define ADD(a, b) (a) +(b)
这三种定义,全部都是不符合要求的。陷阱如下:
在计算ADD(a,b)*ADD(c,d)时,显然第一种出问题了。
#define MULTIPLE(a, b) (a*b) 在计算(a+b)*c时,调用MULTIPLE(a+b,c)得到的结果错误。
因此一定要使用完备的括号,如下示例:
#define ADD(a,b) ((a) + (b))
2,使用宏定义,不允许参数发生变化,这也就是带参数的宏定义和函数的区别:
如下测试源码:
#include <stdio.h> #define sqrt(a) ((a)*(a)) int fsqrt(int a) { return a*a; } int main() { int a = 10, b = 10; int r1, r2; r1 = sqrt(a++); r2 = fsqrt(b++); printf("a = %d, b = %d, r1 = %d, r2 = %d\n", a, b, r1, r2); return 0; }
最终的结果是a = 12; b = 11; r1 = 100; r2 = 100; 以上结果在vc6.0下获得。之所以a变成12,是因为在替换的时候,a++被执行了两次。要避免这种行为,就要使宏参数不发生变化。
如:a++; r1 = sqrt(a), 一切就ok了!
3,使用大括号将宏定义包含的多条表达式括起来。
如下示例:
#include <stdio.h> #define INITIAL(a, b)\ a = 0;\ b = 0; int main() { int a[5], b[5] ; int i; for(i=0; i<5; i++) INITIAL(a[i], b[i]); printf("a = %d, b = %d\n", a[0], b[0]); return 0; }
结果打印a是正常的,但打印b却是未初始化的结果。因为简单的文本替换,不能保证多条表达式都放到for循环体内。(这里,如果单独初始化一个变量,没有for循环时没有问题的。)上述的宏定义应改为:
#define INITIAL(a, b)\ {\ a = 0;\ b = 0;\ }
注意这个“\”号哦,表示下面的一行和当前行在预编译时被认为在同一行。
最后,再简单对比下#define和 typedef的区别,#define发生在预编译阶段, typedef发生在编译阶段,可参考http://topic.csdn.net/t/20030810/14/2129718.html。更多细节上的区别,稍后再谈。
不对之处,大家多指正。
相关文章推荐
- 关于使用git一点额外总结
- 分享关于php CI框架使用的一点小总结
- iOS关于rar解压第三方库Unrar4iOS使用总结
- 关于jenkins的使用问题总结
- 关于DevExpress的XtraTreeList使用方法总结
- 关于debug使用的总结
- 关于svn下 cocopods使用经验总结
- 关于JNI的使用总结
- java和struts使用中的一点总结--关于写在页面上的select域的选项选中后保存状态的办法!
- django1.6 使用userprofile 以及一些关于用户系统的总结
- 关于后台动态模板添加内容的总结 Builder使用
- 项目中关于AJAX的使用总结
- 文件搜索神器everything 的技巧总结以及关于Archive Searcher搜素压缩包内文件使用
- 关于Yaf框架的使用总结
- 关于使用QTcpSocket的一些总结
- 关于DevExpress的XtraTreeList使用方法总结
- 关于jeesite开源项目的一些使用总结
- 关于web对话窗口使用总结
- 关于NRF24L01模块使用的部分个人总结
- 关于信号量的使用总结