如果我给一个无符号变量赋一个负值会怎样?


81

我很想知道如果我给一个无符号变量赋一个负值会发生什么。

该代码将看起来像这样。

unsigned int nVal = 0;
nVal = -5;

它没有给我任何编译器错误。当我运行程序时,它nVal被分配了一个奇怪的值!可能是某些2的补码值分配了nVal吗?


1
我的直觉(尚未在标准中找到它)是行为在技术上是不确定的。此外,我怀疑您会在几乎所有可以找到的编译器上看到期望的结果。因此,尽管您通常会看到这种行为,但依靠它可能不是一个好主意。
2010年

6
它不是未定义的(请参阅第4.7 / 2节),但标准并未规定表示形式(例如2s补码)。
Georg Fritzsche 2010年

@gf(下面等),很酷。实际上,该行为似乎已明确定义为您期望的@viswanathan。
2010年

3
第二行等效于nVal = (unsigned int) -5;。的演员-5unsigned int定义在6.3.1.3。标准不要求以2s补码表示。但是要转换为无符号的算法是:“通过重复添加或减去比新类型可以表示的最大值多一的值来转换值,直到该值在范围内为止。的新类型。”
Pascal Cuoq 2010年

1
@Pascal:您似乎是在指C99,但问题被标记为C ++。
Georg Fritzsche 2010年

Answers:


67

官方答案-4.7转换积分

“如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(取模2 n,其中nn是用于表示无符号类型的位数)。[注意:在二进制补码形式中,此转换是概念性的,并且位模式没有任何变化(如果没有截断的话)。

从本质上讲,这意味着,如果基础体系结构存储的方法不是Two's Complement(如符号幅度或One's Complement),则到无符号的转换必须表现为好像是Two's Complement。


37
什么是最无符号整数一致的源整数意味着什么?
DavidRodríguez-dribeas

11
@DavidRodríguez-dribeas作为一个例子,图5和3是“全等模2”,因为5%2和3%2都为1
JoeQuery

它涉及哪些版本的C ++标准?所有?
Alexey Kruglov

36

它将代表-5(以2的补码表示)的位模式分配给无符号的int。这将是一个很大的无符号值。对于32位整数,这将是2 ^ 32-5或4294967291


2
位与它无关。
GManNickG

1
@BenVoigt:公平地说,我的意思是它与位的解释无关。(也就是说,引用的部分中的“位”仅是简写ceil(log_2(x))。)
GManNickG 2012年

1
@GManNickG位的(例如,属于该位)?2的赞美(对您很好)?GAAAAAAAAAAAAAH!
NullUserException 2012年

1
@NullUserException:哈哈,我知道。用“ *”代替“ * s”是我一段时间以来的一个糟糕习惯。至于赞美而不是补语,那纯粹是愚蠢的行为。:)
GManNickG 2012年

简洁是关键。这个答案有。(2 ^ 32-5)比引用文档更好地解释了此行为。
Redhart

4

它将显示为最大无符号整数-4(值取决于计算机体系结构和编译器)的正整数。

顺便说一句,
您可以通过编写一个简单的C ++“ hello world”类型程序来检查此内容,并亲自看看


我写过并检查了它,这就是为什么我问这个问题,但是我不知道编译器是如何达到那个正值的。谢谢
ckv

6
不幸的是,对于C ++,编写测试行为的程序并不总是一个好主意。例如,如果尝试测试有符号溢出的情况,将会导致未定义的行为,并不能保证每台机器/编译器都相同。
本·琼斯

4

没错,有符号整数以2的补码形式存储,符号整数以无符号二进制表示形式存储。C(和C ++)无法区分这两者,因此最终得到的值只是2的补码二进制表示形式的无符号二进制值。


16
它可能不存储在2的补语中。
GManNickG

如果某物“以2存储”是什么意思?@GManNickG
JeremyF 2014年

4
@JeremyF:不是“ 2的”,“ 2的恭维”。这是Google可以使用的术语,也是表示有符号整数的一种方式。
GManNickG 2014年

2

是的,你是对的。分配的实际值类似于除第三个位以外的所有其他位。-1是设置的所有位(十六进制:0xFFFFFFFF),-2是除第一个以外的所有位,依此类推。您将看到的可能是十六进制值0xFFFFFFFB,其十进制对应于4294967291。


3
位与它无关,未指定整数表示。
GManNickG 2010年

2
您的回答是正确,严谨的,这是我在课堂上永远不会使用的。
马丁

看到我的答案是-5的2的补码。我认为您在此处对二进制值的运算不正确。
cynistersix 2011年

0

当您为无符号变量赋负值时,它使用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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.