##
连接符、 #
符 和 __VA_ARGS__
的使用#
When you put a # before an argument in a preprocessor macro, the preprocessor turns that argument into a character array.
将#
置于预处理宏的某个参数之前,预处理器会把这个参数转化为一个字符数组处理。
简化理解:#
是“字符串化”的意思,出现在宏定义中的#
是把跟在后面的参数转换成一个字符串。
#define ERROR_LOG(module) fprintf(stderr, "error: "#module"\n")
ERROR_LOG("add");
将转化为fprintf(stderr, "error: add\n");
ERROR_LOG(devied=0);
将转化为`fprintf(stderr, “error:devied=0\n”);
举个例子,如下:
#include
#define PSQR(x) printf("The square of" #x " is %d.\n", (x)*(x))
int main(void)
{
int y = 4;
PSQR(y);
PSQR(2+4);
return 0;
}
输出结果:
The square of y is 16.
The square of 2+4 is 36.
第一次调用宏使用y
代替#x
;第二次调用使用2+4
代替#x
。
##
“##”是一种分隔连接方式,它的作用是先分隔,替换然后进行强制连接。
在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就替换。这样做的结果是,被替换段之间存在一些空格。如果我们不希望出现这些空格,就可以通过添加一些##
来替代空格。
#define TYPE1(type, name) type name_##type##_type
#define TYPE2(type, name) type name##_##type##_type
TYPE1(int, c);
转换为int name_int_type;
(因为##
号将后面分为 name_
、type
、 _type
三组,替换后强制连接)
TYPE2(int, d);
转换为int d_int_type;
(因为##号将后面分为 name
、_
、type
、_type
四组,替换后强制连接)
举个例子:
#define
#define XNAME(n) x##n
#define PXN(n) printf("x"#n"=%d\n", x##n)
int main(void)
{
int XNAME(1)=12; /* int x1=12; */
PXN(1); /*printf("x1=%d\n", x1);*/
return 0;
}
输出结果:
x1=12
下面给出一个##
与位移操作结合的经典例子,可以背下来,平时写程序的时候用得上。例子如下:
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)
#define BIT_MASK(_bf) ( ( (1U << (bw##_bf)) - 1) << (bs##_bf))
#define SET_BITS(_dst, _bf, _val) \
( (_dst) = ( (_dst) & ~(BIT_MASK(_bf)) ) | \
( ((_val) << (bs##_bf)) & (BIT_MASK(_bf)) ) )
SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumbers);
一起来一点点看这个宏怎么展开,SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumbers);
中
MCDR2
替换_dst
,
MCDR2_ADDRESS
替换_bf
,
RegisterNumbers
替换_val
,
SET_BITS(_dst, _bf, _val)
就变成了:
( (MCDR2) = ( (MCDR2) & ~(BIT_MASK(MCDR2_ADDRESS)) ) | ( ((RegisterNumbers) << (bsMCDR2_ADDRESS)) & (BIT_MASK(MCDR2_ADDRESS)) ) )
根据#define BIT_MASK(_bf) ( ( (1U << (bw##_bf)) - 1) << (bs##_bf))
,进一步替换得到
( (MCDR2) = ( (MCDR2) & ~( ( ( (1U << (bwMCDR2_ADDRESS)) - 1) << (bsMCDR2_ADDRESS)) ) | ( ((RegisterNumbers) << (bsMCDR2_ADDRESS)) & ( ( ( (1U << (bwMCDR2_ADDRESS)) - 1) << (bsMCDR2_ADDRESS)) ) ) )
将#define bwMCDR2_ADDRESS 4
和#define bsMCDR2_ADDRESS 17
带入上述表达式,得到:
( (MCDR2) = ( (MCDR2) & ~( ( ( (1U << (4)) - 1) << (17)) ) | ( ((RegisterNumbers) << (17)) & ( ( ( (1U << (4)) - 1) << (17)) ) ) )
其中( ( (1U << (4)) - 1) << (17)) )
算出二进制数1111 0000 0000 0000 0000 0
;~( ( ( (1U << (4)) - 1) << (17)) )
则为0000 1111 1111 1111 1111 1
。
上述表达式又变为:
( (MCDR2) = ( (MCDR2) & 0000 1111 1111 1111 1111 1) | ( (RegisterNumbers) << (17) & 1111 0000 0000 0000 0000 0 )
最后应该是MCDR2
=(MCDR2
的低17位,加上RegisterNumber
的低四位作为MCDR2
的高4位)
#include
#define bwMCDR2_ADDRESS 4
#define bsMCDR2_ADDRESS 17
#define bmMCDR2_ADDRESS BIT_MASK(MCD2_ADDRESS)
#define BIT_MASK(_bf) ( ((1U << (bw##_bf)) - 1) << (bs##_bf) )
#define SET_BITS(_dst, _bf, _val) \
(_dst) = ( (_dst & ~(BIT_MASK(_bf))) | \
( ((_val) <<(bs##_bf)) & ( BIT_MASK(_bf) ) ) )
void
main()
{
unsigned dst = 0x1ffff;
unsigned regnum = 0x8;
printf("%x\n", BIT_MASK(MCDR2_ADDRESS)); /*0x1e0000*/
SET_BITS(dst, MCDR2_ADDRESS, regnum);
printf("%x\n", dst); /*11ffff*/
}