跳至内容
响水凹
欢迎来到 Guang-Wen Duan (Dennis Duan) 的个人 Wiki
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
computer:c:tips:macro_with_parameters
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 参数宏(Macro with parameters) ====== ===== 括号规则 ===== 对于带参数的宏,定义时左括号(parenthesis)必须紧接着宏名,之间不能有空格,否则,从左括号开始的部分都被识别为宏的定义。当运行时,宏名和左括号之间可以有空白。 宏调用时,实参可以包含多层括号,括号内可以有逗号(commas)。大括号(braces)和中括号(brackets)也可以出现在实参里,但他们里面不能包含逗号。 例如定义: <code> #define insert(stmt) stmt </code> 如下调用是合法的: <code c> insert( { a = 1; b = 1; } ) </code> 但这个就不行: <code c> insert( { a = 1, b = 1; } ) </code> 必须写成这样才行: <code c> insert( { (a = 1, b = 1); } ) </code> 有点诡异,但这是语法的要求。 ===== 宏的本质 ===== 编写带参数的宏需要特别小心,因为**宏扩展的本质仅仅是进行文本式的替换(textual substitution)**,它不是真正的函数。 例如: <code> #define SQUARE(x) x * x </code> 本意是求平方,但调用: <code c> SQUARE(z + 1) </code> 的扩展结果却是: <code c> z + 1 * z + 1 </code> 一个安全的做法是在宏体内使用括号括住每个参数。如果整个宏的形式是一个表达式,那么宏也用括号括住。 上例改造后: <code> #define SQUARE(x) ((x) * (x)) </code> 如果没有用括号括住整个宏,那么下面的调用仍旧可能会出问题: <code c> (short)SQUARE(z + 1) </code> 因为强制转换的优先级更高。 ===== 宏的副作用 ===== 括号不是万能的,还要注意宏参数可能存在的副作用,毕竟宏不是函数。 例如: <code c> a = 3; b = SQUARE(a++); </code> 导致a++了两次,结果为5,而b的结果则依赖于实现。如果SQUARE是个函数,就不会有这个问题。 ===== do-while模式 ===== 对于多语句的情况,一般用do-while结构比较合适。 比如下面的实现: <code> #define swap(x, y) {unsigned long temp = x; x = y; y = temp;} </code> 实际调用时,很容易在末尾加个分号(semicolon),导致编译出错: <code c> if ( x > y) swap(x, y); else x = y; </code> 改用do-while实现就好了: <code> #define swap(x, y) \ do { unsigned long temp = x; x = y; y = temp; } while (0) </code> ===== 变参宏 ===== C99允许在参数中使用%%...%%实现变参宏。所有额外的参数,包含其中的逗号,用标识符%%__VA_ARGS__%%代替。 比如: <code> #define my_printf(...) fprintf(stderr, __VA_ARGS__) </code> 调用: <code c> my_printf("x = %d\n", x); </code> 的扩展结果为: <code c> fprintf(stderr, "x = %d\n", x); </code> 另一个例子: <code> #define make_em_a_string(...) #__VA_ARGS__ </code> 调用: <code c> printf("%s\n", make_em_a_string(a, b, c, d)); </code> 的扩展结果为: <code c> printf("%s\n", "a, b, c, d"); </code> {{tag>C语言}}
computer/c/tips/macro_with_parameters.txt
· 最后更改: 2014/11/01 02:02 由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部