我正在阅读一些例子,并且在所有这些例子中都使用了unsigned。如果使用正确,使用int类型是否安全?与下面的示例中一样,0x12345678地址将写入0xFFFFFFFF,而不管ptr被定义为有符号还是无符号。
volatile unsigned int* ptr = (volatile unsigned int* ) 0x12345678;
*ptr = 0xFFFFFFFF;
为什么使用unsigned而不是signed来进行寄存器访问是安全的?
答案 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将此值解释为有符号或无符号数。