使用宏的一些注意
2004-10-15 15:14
337 查看
1。 宏是一种替换,是C预处理器在编译前完成的。
2。 宏文本替换和typedef之间的区别:
比如typedef int x[10]和#define x int[10]之间的区别
(1) 可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做。
eg,
#define peach int
unsigned peach i; /* No problem, ^_^ */
typedef int banana;
unsigned banana i; /* Error, Invalid, :-) */
(2) 连续声明几个变量时,用typedef定义的类型能够保证声明中所有的变量均为同一类型,而用#define定义的类型则无法保证。
eg,
#define int_ptr int *
int_ptr apple, cheese;
宏扩展后,变为: int * apple, cheese;
使得apple和Cheese成为不同的类型,一个是int型指针,另一个是int型
[ Reference from <<C Expert Programming>> page 68 - 69 ]
将宏用于类型定义这种用法有一个优点 -- 可移植性, 得到所有C编译器的支持。
3。 带参宏与函数,类似但本质不同。就速度而言,宏少了对函数进行调用的开销,会快一点,但因为宏只是进行文本替换,所以代码在频繁使用的地方,
使用宏,code size会增大。所以,写代码时,应该根据系统环境,如运行速度,memory size等的不同,在速度和code size之间找到一个平衡点。
4。 最好在宏定义中把每一个参数都用括号括起来,整个结果表达式也应该用括号括起来,以防止当宏用于一个更大一些的表达式中可能出现的问题。
eg,
#define abs(x) x>0?x:-x
在表达式 abs(a-b)中, 会被展开为 a-b>0?a-b:-a-b
上式无疑会得到一个错误的结果。
正确定义应该这样:
#define abs(x) (((x)>=0)?(x):-(x))
5。 避免使用有副作用的参数作为带参宏的参数,比如++, --,如果++i这个参数在宏中被求值两次
eg,
#define max(x,y) ((x)>(y)?(x):(y))
...
biggest = max(biggest, x[i++]);
展开后为:biggest = ((biggest)>(x[i++])?(biggest):(x[i++]))
如果biggest = 2, x[0] = 2, x[1] = 3, x[2] = 1, i = 1
那么:
i++将被求值两次,比较后i递增为2。如果i是一个函数的counter,
eg,
while (i < n)
biggest = max(biggest, x[i++]);
将导致错误。
在这时使用函数,代码就会work well了。
6。 宏不是语句
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
__FILE__和__LINE__是C预处理器中的宏,会被扩展为所在文件的文件名和所处代码行的行号。
如果这样用:
if (x > 0 && y > 0)
assert(x > y);
else
assert(y > x);
展开后为:
if (x > 0 && y > 0)
if (!(x > y)) assert_error("foo.c", 12);
else
if (!(y > x)) assert_error("foo.c", 16);
缩排一下:
if (x > 0 && y > 0)
if (!(x > y))
assert_error("foo.c", 12);
else
if (!(y > x))
assert_error("foo.c", 16);
[Reference from <<C Traps and Pitfalls>> page 101 - 102]
明显不是所希望的结果。
2。 宏文本替换和typedef之间的区别:
比如typedef int x[10]和#define x int[10]之间的区别
(1) 可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做。
eg,
#define peach int
unsigned peach i; /* No problem, ^_^ */
typedef int banana;
unsigned banana i; /* Error, Invalid, :-) */
(2) 连续声明几个变量时,用typedef定义的类型能够保证声明中所有的变量均为同一类型,而用#define定义的类型则无法保证。
eg,
#define int_ptr int *
int_ptr apple, cheese;
宏扩展后,变为: int * apple, cheese;
使得apple和Cheese成为不同的类型,一个是int型指针,另一个是int型
[ Reference from <<C Expert Programming>> page 68 - 69 ]
将宏用于类型定义这种用法有一个优点 -- 可移植性, 得到所有C编译器的支持。
3。 带参宏与函数,类似但本质不同。就速度而言,宏少了对函数进行调用的开销,会快一点,但因为宏只是进行文本替换,所以代码在频繁使用的地方,
使用宏,code size会增大。所以,写代码时,应该根据系统环境,如运行速度,memory size等的不同,在速度和code size之间找到一个平衡点。
4。 最好在宏定义中把每一个参数都用括号括起来,整个结果表达式也应该用括号括起来,以防止当宏用于一个更大一些的表达式中可能出现的问题。
eg,
#define abs(x) x>0?x:-x
在表达式 abs(a-b)中, 会被展开为 a-b>0?a-b:-a-b
上式无疑会得到一个错误的结果。
正确定义应该这样:
#define abs(x) (((x)>=0)?(x):-(x))
5。 避免使用有副作用的参数作为带参宏的参数,比如++, --,如果++i这个参数在宏中被求值两次
eg,
#define max(x,y) ((x)>(y)?(x):(y))
...
biggest = max(biggest, x[i++]);
展开后为:biggest = ((biggest)>(x[i++])?(biggest):(x[i++]))
如果biggest = 2, x[0] = 2, x[1] = 3, x[2] = 1, i = 1
那么:
i++将被求值两次,比较后i递增为2。如果i是一个函数的counter,
eg,
while (i < n)
biggest = max(biggest, x[i++]);
将导致错误。
在这时使用函数,代码就会work well了。
6。 宏不是语句
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
__FILE__和__LINE__是C预处理器中的宏,会被扩展为所在文件的文件名和所处代码行的行号。
如果这样用:
if (x > 0 && y > 0)
assert(x > y);
else
assert(y > x);
展开后为:
if (x > 0 && y > 0)
if (!(x > y)) assert_error("foo.c", 12);
else
if (!(y > x)) assert_error("foo.c", 16);
缩排一下:
if (x > 0 && y > 0)
if (!(x > y))
assert_error("foo.c", 12);
else
if (!(y > x))
assert_error("foo.c", 16);
[Reference from <<C Traps and Pitfalls>> page 101 - 102]
明显不是所希望的结果。
相关文章推荐
- ios storyboard使用的一些注意事项
- JavaScript使用过程中需要注意的地方和一些基本语法
- 【Php】在函数内部使用unset的一些注意点
- 使用继承机制要注意的一些问题
- Android控件使用—EditText的一些注意事项
- Zepto 使用中的一些注意点
- 使用prototype的 ajax时,编码上的一些注意
- css属性使用中的一些注意事项
- 关于使用存储过程的一些好处以及注意事项
- 使用源码编译3D Slicer3的一些注意事项
- android 新手使用时的一些小注意事项
- Unity+NGUI使用时一些要注意的事整理(持续更新)
- ~ 使用redis缓存数据需要注意的问题以及个人的一些思考和理解
- 关于CKEditor与CKFinder配合使用以及一些注意点总结
- 使用Kubernetes需要注意的一些问题(FAQ of k8s)
- 使用Linux raw socket时需要注意的一些问题
- Oracle Dependency 使用要注意的一些问题。
- 使用反射调用匿名内部类时应该注意的一些地方
- 使用ROR组建系统时的一些注意点(持续追加中)
- Oracle数据库存储过程使用中一些注意事项