unsigned int addr = 0x1000;
int temp = *((volatile int *) addr + 3);
它是否将递增的指针(即addr + 3 * sizeof(int)
)视为指向volatile int
的指针(在解除引用时)。换句话说,我可以期望在temp?
0x1012
)的内容
答案 0 :(得分:3)
是
指针运算不会影响指针的类型,包括任何类型限定符。给定A + B
形式的表达式,如果A
具有指向T的类型限定指针且B
是一个整数类型,则表达式A + B
也将是一个限定指针T - 相同类型,相同的限定符。
从C规范的6.5.6.8(草案n1570):
当指针中添加或减去具有整数类型的表达式时, result具有指针操作数的类型。
答案 1 :(得分:2)
假定addr
是一个整数(变量或常量),其值可以实现,可以安全地转换为int *
(见下文)。
考虑
volatile int a[4] = [ 1,2,3,4};
int i = a[3];
除了显式转换 integer 到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
的代码)都会与她的团队负责人进行非常认真的对话。
答案 2 :(得分:1)
首先请注意,从整数到指针的转换不一定是安全的。它是实现定义会发生什么。在某些情况下,这样的转换甚至可以调用未定义的行为,以防整数值不能表示为指针,或者如果指针最终带有错位的地址。
使用整数类型uintptr_t
来存储指针和地址更安全,因为它可以保证能够存储给定系统的指针。
鉴于您的编译器为此代码实现了安全转换(例如,大多数嵌入式系统编译器都这样做),那么代码确实会按预期运行。
指针算法将在volatile int
的类型上完成,因此+ 3
表示将地址增加sizeof(volatile int) * 3
个字节。如果您的系统上int
为4个字节,则最终会读取地址0x100C
的内容。不知道你从哪里得到0x1012
,混合了十进制和十六进制表示法?