在增量之后取消引用指向volatile int的指针

时间:2016-04-15 00:41:47

标签: c pointers linux-device-driver volatile low-level-io

unsigned int addr = 0x1000;    
int temp = *((volatile int *) addr +  3);

它是否将递增的指针(即addr + 3 * sizeof(int))视为指向volatile int的指针(在解除引用时)。换句话说,我可以期望在temp?

中硬件更新say(0x1012)的内容

3 个答案:

答案 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,混合了十进制和十六进制表示法?