在缺乏引用支持的C语言中,有的时候定义宏几乎成了唯一的选择,虽然有人认为引用代表了一种不怎么明确的语义:不知道参数是否可能会更改,但是如果引用施加于一个语义明确的对象,比如流,那么一切也就无可厚非了。
请看下面一段代码:
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#define get_u16(addr) ({ uint16_t **p = (uint16_t**)&(addr); *(*p)++; })
int main(int argc, char *argv[])
{
uint16_t a[] = {12, 13};
char *ptr = (char*)a;
printf("% " PRIu16 "\n", get_u16(ptr));
printf("% " PRIu16 "\n", get_u16(ptr));
return 0;
}
|
get_u16的参数被当成了字节流的地址,每次调用它除了返回一个16比特的无符号整形外,数据流也会做相应的改变,可以认为get_u16吃掉并返回了16比特的无符号整形。上面代码运行正常:
稍作改变,将ptr改成p,编译后运行:
xiaosuo@gentux ~ $ ./a.out 56984 56976
|
问题出现了,怎么会是这个结果呢?为了一探究竟我们不妨用cpp将宏展开来看:
int main(int argc, char *argv[])
{
uint16_t a[] = {12, 13};
char *p = (char*)a;
printf("% " "u" "\n", ({ uint16_t **p = (uint16_t**)&(p); *(*p)++; }));
printf("% " "u" "\n", ({ uint16_t **p = (uint16_t**)&(p); *(*p)++; }));
return 0;
}
|
不难发现,本来应该是宏参数的变量被宏内部的变量覆盖了,根据C对作用域的定义,在宏内部用到的就是自己的变量,实际上我们应该庆幸,上面的代码没有断错误退出,多少给我们留足了面子。
问题的原因找到了,如何解呢?恕在下愚笨,着实没有找到完美的解决方法,只想到了借助编程惯例:
除非是库,否则不应该定义以_开始的变量,这样的话,get_u16可以这样定义:
#define get_u16(addr) ({ uint16_t **_p = (uint16_t**)&(addr); *(*_p)++; })
|
结论:因为宏毕竟不是函数,所以
在其内部定义变量的时候要格外小心,最好在变量名前加上_,以防止覆盖外部变量,造成意外。
阅读(5056) | 评论(5) | 转发(0) |