我在网站上找到了这个代码段:
#define DISPLAY_CR (*(volatile unsigned int *) 0x4000000)
DISPLAY_CR = somevalue;
应该将DISPLAY_CR描述为指向地址0x4000000的易失性无符号int指针
我不明白的原因是:
答案 0 :(得分:6)
额外的括号是宏中的标准做法。宏以复制和粘贴的方式进行扩展,因此如果没有括号,precedence可能会根据上下文进行更改。
忽略额外的括号,您的代码将扩展为:
*(volatile unsigned int *) 0x4000000 = somevalue;
相当于:
volatile unsigned int *p = 0x4000000; // Treat this as the address of a volatile unsigned int
*p = somevalue; // Write to that address
希望更清楚。
答案 1 :(得分:2)
额外的括号是阻止宏被周围的令牌破坏。 'stars'用于将地址转换为指针,然后取消引用它,以获取其地址的值
答案 2 :(得分:2)
你有
0x4000000
- 地址0x4000000 (volatile unsigned int *) 0x4000000
- 强制转换为易失性指针* (volatile unsigned int *) 0x4000000
- 取消引用制作左值的指针(*(volatile unsigned int *) 0x4000000)
- 包含一组额外的括号,以便DISPLAY_CR
实际上是一个单一的令牌 - 你不会遇到运算符优先级问题等等。答案 3 :(得分:2)
整个表达式的括号对于所有宏都很重要,对于像列出的宏一样重要。
如果有人要写,请说:
int foo = DISPLAY_CR++;
并且没有括起宏的括号,它将解析为:
int foo = *(volatile unsigned int *)(0x4000000++);
具有完全不同的含义。
答案 4 :(得分:1)
此宏未将DISPLAY_CR
描述为指向地址0x4000000
的volatile unsigned int指针。它将DISPLAY_CR
描述为位于0x4000000
的无符号整数值,最有可能是硬件专用寄存器。
您需要volatile
的原因是为了防止编译器“优化”对硬件寄存器的多次写入。例如,如果您需要通过将值设置为1然后清除它来向硬件发出信号,那么您可以编写
DISPLAY_CR = 1;
DISPLAY_CR = 0;
如果没有volatile
,编译器可能会将第一个赋值放在无关紧要的位置; volatile
阻止它这样做。
答案 5 :(得分:0)
内部的星号表示该类型是指向unsigned int的指针。外星将指针指向它所指向的记忆单元。
答案 6 :(得分:0)
好的,让我们分解一下。
显然,0x4000000
是一个数字,我们想用它来指定一个特定的内存地址(希望那里有重要的东西)。
现在,(volatile unsigned int *)
是强制转换,这意味着它告诉编译器强制将参数类型强制为指定类型(指向无符号整数的指针,volatile)
最后,*
是解除引用运算符。这意味着我们想要访问存储在该地址中的值。
使用宏时,额外的括号只是好的风格 - C程序员特别防守它们,因为运算符优先级规则有点令人困惑。