我无法理解两个无符号整数之间的简单算术运算;为什么结果为“802
”?
假设整数数字大小为32
- 由编译器保证的位。
#include <stdio.h>
#include <stdint.h>
int main(int argc, char const *argv[])
{
uint32_t Temp1;
Temp1 = (uint32_t)801 - (uint32_t)0xFFFFFFFF; // Two Unsigned Integers
uint32_t Temp2;
Temp2 = 801 - 0xFFFFFFFF;// Two Signed Integers and result assigned to unsigned
unsigned int Temp3;
Temp3 = (unsigned int)((unsigned int)801 - (unsigned int)0xFFFFFFFF); // Two Unsigned Integers
int32_t Temp4;
Temp4 = 801 - 0xFFFFFFFF;// Two Signed Integers
printf("Temp1: %d %u\n",Temp1,Temp1 );
printf("Temp2: %d %u\n",Temp2,Temp2 );
printf("Temp3: %d %u\n",Temp3,Temp3 );
printf("Temp4: %d %u\n",Temp4,Temp4 );
return 0;
}
输出:
Temp1: 802 802
Temp2: 802 802
Temp3: 802 802
Temp4: 802 802
如果我将表达式置于if
条件下,编译器将如何处理它?它会将表达式((uint32_t)OPERAND_1 - (uint32_t)0xFFFFFFFF)
转换为有符号整数还是无符号整数,然后进行求值?
if(((uint32_t)801 - (uint32_t)0xFFFFFFFF) > (uint16_t)1500)
{
printf("Hello All\n");
}
else
{
printf("Hello None\n");
}
答案 0 :(得分:4)
假设0xFFFFFFFF
为32位,十六进制常量int
的类型为unsigned int
。因此,当在801
的表达式中使用int
时,由于通常的算术转换unsigned int类型>
以上示例中的任何一点都没有对签名类型进行算术运算,因此没有关于签名环绕或负数表示的实现定义行为。
C standard的第6.3.1.8节说明了关于整数类型转换的以下内容:
如果两个操作数具有相同的类型,则不再进一步转换 需要的。
否则,如果两个操作数都有有符号整数类型或两者都有 无符号整数类型,类型较小的操作数 整数转换等级转换为操作数的类型 排名更高。
否则,如果具有无符号整数类型的操作数具有 等级大于或等于另一个类型的等级 操作数,那么带有符号整数类型的操作数是 转换为带无符号整数的操作数类型 类型。强>
否则,如果带有符号整数类型的操作数的类型可以 表示带有unsigned的操作数类型的所有值 整数类型,那么带无符号整数类型的操作数是 转换为带有符号整数类型的操作数类型。
否则,两个操作数都转换为无符号
整数类型对应于带有signed的操作数的类型 整数类型
第三段是在这种情况下生效的段落,因为int
和unsigned int
具有相同的等级。这意味着上面的所有算术都是在unsigned int
类型上完成的。
这种类型的操作发生模2 32 ,这实际上意味着值环绕。从0xFFFFFFFF
中减去801
包围到导致802,这是在所有情况下都会被打印的内容。
为了详细说明环绕行为,我们以无符号3位整数类型为例,其值为0到7.假设我们用这种类型计算3 - 7。这类似于您正在进行的减法,因为减去的值是数据类型可以容纳的最大值。
现在我们减去:
注意一旦第二个操作数大于第一个操作数,值如何包围,并且该有效结果与添加1相同。这与示例中的相同。
答案 1 :(得分:2)
在C中,无符号算术以模2 ^ n完成,其中n是无符号整数的位数。
答案 2 :(得分:1)
大多数情况下,计算机使用所谓的2补码来表示有符号整数。对于4个字节的int,0xFFFFFFFF
为-1
。
Two's complement - Wikipedia
#include <stdio.h>
#include <stdint.h>
int main(int argc, char const *argv[])
{
uint32_t Temp1;
Temp1 = (uint32_t)801 - (uint32_t)0xFFFFFFFF; // Two Unsigned Integers
uint32_t Temp2;
Temp2 = 801 - 0xFFFFFFFF; // Two Signed Integers and result assigned to unsigned
unsigned int Temp3;
Temp3 = (unsigned int)((unsigned int)801 - (unsigned int)0xFFFFFFFF); // Two Unsigned Integers
int32_t Temp4;
Temp4 = 801 - 0xFFFFFFFF; // Two Signed Integers
printf("Temp1: %d %X %u %d\n",Temp1,Temp1, Temp1, 0xFFFFFFFF );
printf("Temp2: %d %X %u %X\n",Temp2,Temp2, Temp2, 0xFFFFFFFF );
printf("Temp3: %d %X %u %u\n",Temp3,Temp3, Temp3, 0xFFFFFFFF );
printf("Temp4: %d %X %u %x\n",Temp4,Temp4, Temp4, 0xFFFFFFFF );
return 0;
}
输出:
Temp1: 802 322 802 -1
Temp2: 802 322 802 FFFFFFFF
Temp3: 802 322 802 4294967295
Temp4: 802 322 802 ffffffff
答案 3 :(得分:0)
在时钟算术中,如果您将一组数字加到模数减去1,则净效果与添加1相同。另一方面,将模数减1减去数字会产生加1的效果。如果你减去11h到06h你就会得到07h的时钟。在这种情况下,您将2^32 - 1
减去801
,这应该是负数。为了保留无符号,您必须在结果中添加2^32
,以使数字符合0..2^32-1
范围,即801 - (2^32 - 1) + 2^32 = 801 - 2^32 + 2^32 -(-1) = 802
。