让人懵逼的宏定义赋值

  先上源代码:

  文件为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驱动控制寄存器的代表。

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

  最后祝大家身体健康~

时间: 2024-11-04 10:36:56

让人懵逼的宏定义赋值的相关文章

指针直接赋值为整型AND利用宏定义求结构体成员偏移量

首先我们要更正一个很熟悉的概念,那就是指针不仅仅是“地址”,指针还有一个很重要的特性,那就是“类型”. 指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是 int *p = 0; 除外,该语句表示指针为空): 所以 int *p = 10; 这样的代码是不允许的.在C++里面直接是error的,即使在一些C编译器中以warning的形式提示,但是warning有的时候也很严重.所以这种东西不要用.从const int到int*是不存在隐士转换的.

宏定义能否被赋值

计算机科学里的宏(Macro),是一种批量批处理的称谓.一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串).这种替换在预编译时进行,称作宏展开. 发现定义中有意思的点在于这个“语法替换”,. 当宏定义值本身为常量时,这个宏就替换为一个常量, 如:“#define MACRO_B 200”,MACRO_B就不可以被重新赋值. 当宏定义本身代表了一个变量时,这个宏就替换了这个变量,也就同时拥有了该变量可以被赋值的特

C语言中宏定义使用方法详解

C语言中的宏替换详解 首先看一个问题: #include <stdio.h> #define    PRINT_CLINE()    printf("%d", ______) int main(void) { PRINT_CLINE(); PRINT_CLINE(); return 0; } 在横线处填上适当的代码,使得上面这段代码的输出为34. 我想一般人看到这个问题的时候头脑里都没有明确的思路来解答这个它.我看到这个问题的时候想出了各种办法来解答它,最终还是没有通过编译

宏定义的黑魔法 - 宏菜鸟起飞手册

转载:https://onevcat.com/2014/01/black-magic-in-macro/ 宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在业务逻辑上,似乎对宏的使用和依赖并不多.但是使用宏定义的好处是不言自明的,在节省工作量的同时,代码可读性大大增加.如果想成为一个能写出漂亮优雅代码的开发者,宏定义绝对是必不可少的技能(虽然宏本身

&lt;28&gt;【了解】10-枚举类型介绍及定义+【掌握】11-枚举变量变量定义和使用+【掌握】13-typedef定义新的类型+【掌握】15-宏的概念及无参宏定义方法+【掌握】16-有参宏定义和使用方法+【掌握】17-应用:使用有参宏求最大值+【掌握】18-typedef和#define的区别

[了解]10-枚举类型介绍及定义 枚举类型: C语言提供了一个种类型,这种类型的变量的取值被限定在一定的范围之内了 枚举类型的定义: enum 枚举类型名{ 枚举值1,枚举值2,.... }; 举例: 定义一个变量,保存一周的第几天 enum weekday{ zhouyi,zhouer,zhousan,zhousi,zhouwu ,zhouliu,zhouri }; 定义iPhone手机的颜色 关于枚举类型元素的命名习惯 enum iColor{kIcolorWhite,kIcolorBlac

iOS开发笔记--宏定义的黑魔法 - 宏菜鸟起飞手册

宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在业务逻辑上,似乎对宏的使用和依赖并不多.但是使用宏定义的好处是不言自明的,在节省工作量的同时,代码可读性大大增加.如果想成为一个能写出漂亮优雅代码的开发者,宏定义绝对是必不可少的技能(虽然宏本身可能并不漂亮优雅XD).但是因为宏定义对于很多人来说,并不像业务逻辑那样是每天会接触的东西.即使是能偶尔使

iOS 7:漫谈#define 宏定义(转)

iOS 7:漫谈#define 宏定义 #define宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在业务逻辑上,似乎对宏的使用和依赖并不多.但是使用宏定义的好处是不言自明的,在节省工作量的同时,代码可读性大大增加. 如果想成为一个能写出漂亮优雅代码的开发者,宏定义绝对是必不可少的技能(虽然宏本身可能并不漂亮优雅XD).但是因为宏定义对于很多人来

iOS 7:漫谈#define 宏定义

#define宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在业务逻辑上,似乎对宏的使用和依赖并不多.但是使用宏定义的好处是不言自明的,在节省工作量的同时,代码可读性大大增加. 如果想成为一个能写出漂亮优雅代码的开发者,宏定义绝对是必不可少的技能(虽然宏本身可能并不漂亮优雅XD).但是因为宏定义对于很多人来说,并不像业务逻辑那样是每天会接触的东西

【转】C语言中DEFINE简介及多行宏定义

要写好C语言,漂亮的宏定义是非常重要的.宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等. 在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义.那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍. 我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义: #define MAX( a, b) ( (a) > (b) (a) : (b) ) 其次,把它用函数来实现: int max( int a, int b)