C语言特殊宏定义`##`连接符、 `#`符 和 `__VA_ARGS__`的使用

C语言特殊宏定义##连接符、 #符 和 __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 <stdio.h>
#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 <stdio.h>
#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 <stdio.h>

#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*/
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值