4 c programming-languages language-concepts twos-complement unsigned-integer
我是C的初学者.我最近了解了2's Complement
以及其他表示负数的方法,以及为什么2's complement
最合适的方法.
我想问的是,例如,
int a = -3;
unsigned int b = -3; //This is the interesting Part.
Run Code Online (Sandbox Code Playgroud)
现在,用于转换int类型
标准说:
6.3.1.3有符号和无符号整数
当具有整数类型的值转换为除_Bool之外的另一个整数类型时,如果该值可以由新类型表示,则它将保持不变.
否则,如果新类型是无符号的,则通过重复地添加或减去一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内.
第一段不能用作-3
无法表示的段落unsigned int
.
因此第2段开始发挥作用,我们需要知道unsigned int的最大值.它可以在limits.h中找到UINT_MAX.在这种情况下的最大值是这样的计算是:4294967295
-3 + UINT_MAX + 1 = -3 + 4294967295 + 1 = 4294967293
Run Code Online (Sandbox Code Playgroud)
现在4294967293
二进制是11111111 11111111 11111111 11111101
并且-3
在2的补码形式中11111111 11111111 11111111 11111101
它们基本上是相同的位表示,无论我试图分配给无符号整数的负整数,它总是相同的.所以不是无符号类型冗余.
现在我知道printf("%d" , b)
根据标准,这是一种未定义的行为,但这不是一种合理且更直观的做事方式.如果否定被表示为2's Complement
现在,那么代表将是相同的,并且使用的其他方式很少,并且很可能不会在未来的发展中.
因此,如果我们只有一个类型说int,int x = -1
那么现在如果然后%d
检查符号位并且如果符号位是打印负数1
并且%u
总是按原样解释普通二进制数字(位).由于使用,已经处理了加法和减法2's complement
.所以这不是更直观,更简单的做事方式.
输入,输出和计算都很方便.例如,比较和除法有符号和无符号变体(顺便说一句,在无符号和2的补码有符号类型的位级乘法是相同的,就像加法和减法一样,两者都可以编译成CPU的相同乘法指令).此外,无符号运算在溢出的情况下不会导致未定义的行为(除零除外),而签名操作则不会.总的来说,无符号算术是明确定义的,无符号类型只有一个表示形式(不同于三种不同类型的有符号类型,尽管如今,实际上只有一种).
有一个有趣的转折.现代C/C++编译器利用了有符号溢出导致未定义行为的事实.逻辑是它永远不会发生,因此可以进行一些额外的优化.如果它真的发生了,标准说它是未定义的行为,你的错误程序是合法的搞砸了.这意味着你应该避免签名溢出和所有其他形式的UB.但是,有时您可以仔细编写永远不会产生UB的代码,但使用带符号算法比使用无符号算法更有效.
请研究未定义,未指定和实现定义的行为.它们都列在标准末尾的一个附件(J?)中.