unsigned int addr = 0x1000;
int temp = *((volatile int *) addr + 3);
它是否将递增的指针(即addr + 3 * sizeof(int)
)视为指向volatile int
(解除引用时)的指针。换句话说,我可以期待0x1012
temp 中 say () 的硬件更新内容吗?
unsigned int addr = 0x1000;
int temp = *((volatile int *) addr + 3);
它是否将递增的指针(即addr + 3 * sizeof(int)
)视为指向volatile int
(解除引用时)的指针。换句话说,我可以期待0x1012
temp 中 say () 的硬件更新内容吗?
是的。
指针算术不影响指针的类型,包括任何类型限定符。给定一个形式为 的表达式A + B
,如果A
具有指向 T 的类型限定指针并且B
是整数类型,则该表达式A + B
也将是指向 T 的限定指针——相同类型,相同限定符。
从 C 规范(草案 n1570)的 6.5.6.8 开始:
当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。
Presumingaddr
是一个整数(变量或常量),您的实现可以安全地转换为一个值int *
(见下文)。
考虑
volatile int a[4] = [ 1,2,3,4};
int i = a[3];
这完全一样,除了将整数显式转换为volatile int *
(指向...的指针)。对于索引运算符,数组的名称衰减为指向 的第一个元素的指针a
。这是volatile int *
(C 中的类型限定符适用于数组的元素,而不是数组本身)。
这与演员阵容相同。留下2个差异:
将整数转换为“指针”。这是实现定义的,因此如果您的编译器正确支持它(它应该记录这一点),并且值是正确的,那很好。
最后是访问。底层对象不是volatile
,而是指针/resp。使用权。这实际上是标准中的一个缺陷(参见DR476,它要求对象是volatile
,而不是访问。这与记录的意图(阅读链接)和 C++ 语义(应该是相同的)形成对比。幸运的是所有(大多数) 实现按预期生成代码并按预期执行访问。注意这是嵌入式系统上的常见理念。
因此,如果满足先决条件,则代码是正确的。但请参阅下文以获得更好的(在可维护性和安全性方面)选项。
注意:更好的方法是
uintptr_t
保证整数可以保存一个指针,或者 - 更好 -#define ARRAY_ADDR ((volatile int *)0x1000)
后者避免了对整数的意外修改,并清楚地说明了含义。它也可以更容易地使用。它是低级外设寄存器定义中的典型构造。
回覆。你的递增:addr
不是指针!因此,您增加一个整数,而不是一个指针。除了使用真正的指针之外,这更多的是键入,它也容易出错并混淆你的代码。如果需要指针,请使用指针:
int *p = ARRAY_ADDR + 3;
作为个人说明:addr
在一家至少具有一些质量标准的公司中,通过此类代码(带有整数的代码)的每个人都会与她的团队负责人进行非常认真的交谈。
首先请注意,从整数到指针的转换不一定是安全的。将发生什么是实现定义的。在某些情况下,这样的转换甚至可以调用未定义的行为,以防整数值不能表示为指针,或者指针以未对齐的地址结束。
使用整数类型uintptr_t
来存储指针和地址更安全,因为它保证能够存储给定系统的指针。
鉴于您的编译器为此代码实现了安全转换(例如,大多数嵌入式系统编译器都这样做),那么代码确实会按照您的预期运行。
指针运算将在 类型 上完成volatile int
,因此+ 3
意味着将地址增加sizeof(volatile int) * 3
字节。如果int
您的系统上的 an 是 4 个字节,您最终将读取 address 的内容0x100C
。不确定你从哪里得到0x1012
的,混合了十进制和十六进制表示法?