为什么硬件寄存器访问是通过无符号数据类型

时间:2014-11-29 19:49:50

标签: c embedded

我正在阅读一些例子,并且在所有这些例子中都使用了unsigned。如果使用正确,使用int类型是否安全?与下面的示例中一样,0x12345678地址将写入0xFFFFFFFF,而不管ptr被定义为有符号还是无符号。

volatile unsigned int* ptr = (volatile unsigned int* ) 0x12345678; 

*ptr = 0xFFFFFFFF;

为什么使用unsigned而不是signed来进行寄存器访问是安全的?

5 个答案:

答案 0 :(得分:4)

我认为无符号C算法更接近机器寄存器算术。这是因为C语言定义说,如果有符号整数算术运算结果为不符合给定类型(溢出)的数字,则操作的实际结果是未定义的。所以它可以是任何东西。在无符号算术中:

  

涉及无符号操作数的计算可以   永远不会溢出,因为结果无法表示   结果无符号整数类型以模数减少   一个大于可以表示的最大值   得到无符号整数类型。

与机器寄存器中的相同。

你的例子是另一种情况,即行:

*ptr = 0xFFFFFFFF;

创建0xFFFFFFFF类型的常量unsigned long int。类型为unsigned而不是int,因为该值大于最大整数值。如果变量ptr的类型为int*,则编译器需要在分配之前将unsigned转换为signed。这会导致溢出,并且此赋值的结果将是未定义的。虽然我不知道从unsigned转换为int时会生成任何算术运算的编译器。

如果ptr被定义为int*,并且您想要正确,那么您的行应该是:

*ptr = -1;

答案 1 :(得分:3)

大多数硬件寄存器要么不是算术对象(它们可能是位字段而不是语义数字),或者如果它们确实代表一个数字,那么对它们进行语义签名是不常见的(负值对于波特率没有意义)例如除数。)

通常情况下,虽然签名类型在低级别可能没有区别,但它在高级别上没有语义意义。

或许,通常用于处理硬件寄存器值的>>运算符对于签名类型具有实现定义的行为;因此,为了避免混合符号操作以及引入错误的相关隐式转换,在大多数情况下应使用无符号。

我建议除非硬件寄存器是语义符号数字,否则你应该不仅对寄存器使用无符号,而且还要在带有寄存器操作数的表达式中使用操作数。

答案 2 :(得分:1)

答案很简单:您使用的值是无符号的(意味着文字0xFFFFFFFF是无符号的)。您可以将其分配给任何可以保存它的数据类型 - 甚至可以使用float或double。但是,您希望存储无符号值并将其视为无符号值(例如,printf的%x说明符,它打印十六进制值,将其强制转换为无符号值)。那么,如果您的数据在整个过程中未签名,为什么不将其容器的数据类型也取消签名呢?

答案 3 :(得分:0)

您写入的处理器寄存器不知道或不关心编译器如何定义值,只要写入正确的值即可。我赞成这个问题是因为你试图在发布之前找到答案。

答案 4 :(得分:0)

如前所述,未签名或签名以相同方式存储在硬件寄存器中。更高级别的c将此值解释为有符号或无符号数。