我很想知道如果我为无符号变量分配负值会发生什么。
代码看起来有点像这样。
unsigned int nVal = 0;
nVal = -5;
它没有给我任何编译器错误。当我运行程序时,
nVal
被分配了一个奇怪的值!是否有可能某个 2 的补码值被分配给 nVal
?
官方答案 - 第 4.7 节 conv.integral
“如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n,其中
是用于表示无符号类型的位数)。[注:In二进制补码表示,这种转换是概念性的,位模式没有变化(如果没有截断)。—尾注]n
这本质上意味着,如果底层架构存储在不是补码的方法中(例如有符号数或补码),则到无符号的转换必须表现得就像是补码一样。
(C++20 及更高版本要求有符号整数使用 2 的补码,但早期版本的标准允许使用其他表示形式。)
“...全等...”部分意味着您添加或减去 2n 直到该值位于无符号类型的值范围内。对于 2 的补码,这意味着进行 2 的补码符号扩展或截断。对于相同的宽度,位模式不变,因为添加 2n 是无操作:2
n的低
n
位全部为零。 2 的补码加法/减法与无符号的按位运算相同,这就是它的特殊之处。
它将把代表 -5(2 的补码)的位模式分配给 unsigned int。这将是一个很大的无符号值。对于 32 位整数,这将是 2^32 - 5 或 4294967291
你是对的,有符号整数以 2 的补码形式存储,无符号整数以 无符号二进制表示形式 存储。 C(和 C++)不区分两者,因此最终得到的值只是 2 的补码二进制表示形式的无符号二进制值。
它将显示为最大无符号整数 - 4 的正整数值(值取决于计算机体系结构和编译器)。
顺便说一句
您可以通过编写一个简单的 C++“hello world”类型程序来检查这一点并亲自查看
是的,你是对的。分配的实际值类似于除第三位之外的所有位设置。 -1 是设置的所有位(十六进制:0xFFFFFFFF),-2 是除第一个之外的所有位,依此类推。您将看到的可能是十六进制值 0xFFFFFFFB,其十进制对应于 4294967291。
当您为无符号变量分配负值时,它会使用 2 的补码方法来处理它,在该方法中,它将所有 0 翻转为 1,将所有 1 翻转为 0,然后加 1。在您的情况下,您正在处理 4 字节(32 位)的 int,因此它尝试对 32 位数字使用 2 的补码方法,这会导致较高位翻转。例如:
┌─[student@pc]─[~]
└──╼ $pcalc 0y00000000000000000000000000000101 # 5 in binary
5 0x5 0y101
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 # flip all bits
4294967290 0xfffffffa 0y11111111111111111111111111111010
┌─[student@pc]─[~]
└──╼ $pcalc 0y11111111111111111111111111111010 + 1 # add 1 to that flipped binarry
4294967291 0xfffffffb 0y11111111111111111111111111111011