2012-02-13 100 views
2

我发现一个网站上的这个片段:C语言:如何解释这个#define?

#define DISPLAY_CR (*(volatile unsigned int *) 0x4000000) 
DISPLAY_CR = somevalue; 

是应该描述DISPLAY_CR作为挥发性unsigned int的指针ADRESS 0x4000000

我不明白的是为什么:

  • 双括号叠瓦?
  • 两颗星使用(为什么两颗星,而不是只有一个?)

回答

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 

其希望应该是清晰的。

+0

谢谢:)那么两颗星呢:为什么两颗星? – loloof64 2012-02-13 14:01:40

+0

好吧,这很清楚:)非常感谢:) – loloof64 2012-02-13 14:07:55

2

额外括号是从由周围的令牌被破坏停止宏。 的“明星”是要用到的地址转换为指针,然后取消对它的引用,其地址

2

你有

  • 0x4000000来获取值 - 地址0x4000000
  • (volatile unsigned int *) 0x4000000 - 铸易失性指针
  • * (volatile unsigned int *) 0x4000000 - 取消引用指针,使一个左
  • (*(volatile unsigned int *) 0x4000000) - 包裹在一组额外的支架,使DISPLAY_CR是有效罪GLE令牌 - 你不会陷入运算符优先级的问题等周围
+0

谢谢你这个有用的一步一步的解释:) – loloof64 2012-02-13 14:09:06

1

这个宏没有描述DISPLAY_CR作为挥发性unsigned int的指针地址0x4000000。它描述DISPLAY_CR为无符号整数位于0x4000000,最有可能的,特定于硬件的寄存器。

你需要volatile的原因是为了防止编译器“优化”多次写入硬件寄存器。例如,如果你需要将其值设置为1,然后将其清除信号的东西到硬件,你可以写

DISPLAY_CR = 1; 
DISPLAY_CR = 0; 

没有volatile编译器可能下降的第一项任务是微不足道的; volatile阻止它这样做。

+0

谢谢你的易变的“用例”:) – loloof64 2012-02-13 14:26:48

0

星形的内部意味着该类型是指针unsigned int类型。外星取消指向它指向的内存单元的指针。

0

OK,让我们打破下来。

显然,0x4000000是一个数字,我们希望用它来指定一个特定的内存地址(希望这里有重要的东西)。

现在,是铸造,这意味着它告诉编译器来强制参数的类型为指定的类型(这是指针为无符号整数,易失性)。

最后,*是解引用运算符。这意味着我们要访问存储在该地址中的值。

使用宏时,额外的括号只是很好的风格 - 由于运算符优先规则有点令人困惑,C程序员特别对它们是防御性的。

2

围绕整个表达式的括号对于所有的宏都很重要,并且对于像所列出的那样的宏来说是至关重要的。

如果有人写,说:

int foo = DISPLAY_CR++; 

,并且没有括号包围的宏,这将作为解析:

int foo = *(volatile unsigned int *)(0x4000000++); 

它有一个完全不同的含义。