让人懵逼的宏定义赋值

Posted simon3panda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了让人懵逼的宏定义赋值相关的知识,希望对你有一定的参考价值。

  先上源代码:

  文件为portmacro.h,来源于Dynasty项目中的底层代码(NVIC中断控制部分)

 1 #define portNVIC_INT_CTRL_REG        ( * ( ( volatile uint32_t * ) 0xe000ed04UL ) )
 2 #define portNVIC_PENDSVSET_BIT        ( 1UL << 28UL )
 3 
 4 
 5 void vPortYield( void )
 6 {
 7     /* Set a PendSV to request a context switch. */
 8     portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
 9 
10     /* Barriers are normally not required but do ensure the code is completely
11     within the specified behaviour for the architecture. */
12     __DSB();
13     __ISB();
14 }

 

  这一句让我懵逼了.

1 portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;

 宏定义还可以赋值!!?以往的认知都是宏定义为常量,常量不可以被赋值,所以宏一般都是出现在操作符的右侧!!

#define portNVIC_INT_CTRL_REG        ( * ( ( volatile uint32_t * ) 0xe000ed04UL ) )

虽然这句话我可以看懂,portNVIC_INT_CTRL_REG 代表 0xe000ed04UL 地址中的值。为了验证,测试程序如下
 1 #define MACRO_A     ( * ( ( volatile uint32_t * ) 0x20000300 ) )
 2 #define MACRO_B     200
 3 #define MACRO_C      (a)
 4 
 5 int a = 10;
 6 
 7 void MacroTest()
 8 {
 9     int nVal = 50;
10 
11     PWAPP_TRACE(("MACRO_C: %d", MACRO_C));
12 
13     MACRO_C =  20;
14     PWAPP_TRACE(("MACRO_C: %d", MACRO_C));
15     PWAPP_TRACE(("MACRO_A: %d", MACRO_A));
16     PWAPP_TRACE(("address: %d",( * ( ( volatile uint32_t * ) 0x20000300 )) ));
17     MACRO_A = MACRO_B;
18 
19     PWAPP_TRACE(("MACRO_A: %d", MACRO_A));
20     PWAPP_TRACE(("MACRO_B: %d", MACRO_B));
21 
22     MACRO_A = nVal;
23     PWAPP_TRACE(("MACRO_A: %d", MACRO_A));
24 
25     return;
26 }

 

  测试的结果为:

  [PWAPP][MacroTest], line[1230]>>>MACRO_C: 20
  [PWAPP][MacroTest], line[1233]>>>MACRO_C: 20
  [PWAPP][MacroTest], line[1235]>>>MACRO_A: 50
  [PWAPP][MacroTest], line[1236]>>>address: 0
  [PWAPP][MacroTest], line[1240]>>>MACRO_A: 200
  [PWAPP][MacroTest], line[1241]>>>MACRO_B: 200
  [PWAPP][MacroTest], line[1244]>>>MACRO_A: 50

  结果显示还真是可以给宏赋值。

  贴上宏的定义:

  计算机科学里的宏(Macro),是一种批量批处理的称谓。一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串)。这种替换在预编译时进行,称作宏展开。

  发现定义中有意思的点在于这个“语法替换”,。

  当宏定义值本身为常量时,这个宏就替换为一个常量,

    如:“#define MACRO_B 200”,MACRO_B就不可以被重新赋值。

  当宏定义本身代表了一个变量时,这个宏就替换了这个变量,也就同时拥有了该变量可以被赋值的特点,

    如

    #define MACRO_C (a)

    int a = 10;”

  此时MACRO_C代替了整形变量a,同时MACRO_C也可以被赋值。

 

  而#define MACRO_A ( * ( ( volatile uint32_t * ) 0x20000300 ) )实质上和#define MACRO_C (a)是一样的。 * ( ( volatile uint32_t * ) 0x20000300 和a代表的相同的意思。

 

  所以,MARCO是否能够在之后的代码中被赋值,取决于宏在被定义时代表的是常量还是变量。

  其实还有一个很重要的应用问题,虽然MACRO可以被重新赋值,但是在实际代码中使用MACRO来代替变量是否合适呢?也就说应用场景有哪些? 

  常有的用法一般都是用宏来代替常量,因为宏的定义可以清楚的表示该常量的意义。


  而 #define MACRO_A ( * ( ( volatile uint32_t * ) 0x20000300 ) ) 这种用法的个人猜测意义在于可以直接访问硬件地址或驱动的寄存器,在底层的代码中应用的机会会比较多。同时也可以让开发者清楚的知道该地址的意义。如之前的

 

1 #define portNVIC_INT_CTRL_REG        ( * ( ( volatile uint32_t * ) 0xe000ed04UL ) )

 

  就是NVIC驱动控制寄存器的代表。


  目前关于这种宏赋值的用法能想到的基本就只有这些,可能还有其他的应用场景,希望大家能够补充~

  最后祝大家身体健康~

 

以上是关于让人懵逼的宏定义赋值的主要内容,如果未能解决你的问题,请参考以下文章

你觉得Hooks这一点烦吗?

浅谈算法——莫比乌斯反演

mysql 懵逼的状态

12_关于flask中的宏

20180711 懵逼的一天

一篇文章认识Gradle的使命