我很惊讶这个函数为dif1和dif2
产生不同的值void test()
{
unsigned int x = 0, y = 1;
long long dif1 = x - y;
long long dif2 = (int)(x - y);
printf("dif = %lld %lld",dif1,dif2);
}
这是正确的行为吗?在dif1计算中,它首先将32位无符号差异提升为64位无符号值,然后添加符号。是标准行为,不是由语言指定,还是编译器错误?第二种形式是否保证产生-1,或者直到编译器实现?我想最安全的结构是: long long dif3 =(long long)x - (long long)y;
答案 0 :(得分:4)
如果我们假设long long
宽于unsigned int
,那么第一个肯定是定义的。如果不是,则分配给出与答案的第二部分相同的问题。
long long dif1 = x - y;
无符号整数将换行,并且您将获得可以存储在unsigned int中的最大值。
6.2.5 p9:涉及无符号操作数的计算永远不会溢出, 因为无法用结果无符号整数类型表示的结果是 减少模数可以是最大值的数字 由结果类型表示。
至于第二个
long long dif2 = (int)(x - y);
它是实现定义的:
6.3.1.3 p3:否则,新类型已签名,其值无法表示;无论是 结果是实现定义的或引发实现定义的信号。
在这种情况下,unsigned int
的最大值无法在上述规则生效的int
中表示。
答案 1 :(得分:1)
没有什么可以令人惊讶的。
unsigned int x = 0, y = 1;
long long dif1 = x - y;
long long dif2 = (int)(x - y);
第二个与第一个有一点不同:
施放到signed
如果可能,强制转换定义为保留值(UINT_MAX
大于INT_MAX
时不可能),否则实现定义(尽管允许陷阱)
如果我们在演员表上有2s-complement(可能),则演员的结果为-1
。
接下来,我们有一个更宽泛的签名类型的赋值,它总是保持值。