Was passiert, wenn ich einer vorzeichenlosen Variablen einen negativen Wert zuweise?

82

Ich war neugierig zu wissen, was passieren würde, wenn ich einer vorzeichenlosen Variablen einen negativen Wert zuweisen würde.

Der Code sieht ungefähr so ​​aus.

unsigned int nVal = 0;
nVal = -5;

Es gab mir keinen Compilerfehler. Als ich das Programm ausführte, nValwurde dem ein seltsamer Wert zugewiesen! Könnte es sein, dass der Komplementwert einer 2 zugewiesen wird nVal?

ckv
quelle
1
Meine Vermutung (konnte es noch nicht im Standard finden) ist, dass das Verhalten technisch undefiniert ist. Außerdem vermute ich, dass Sie sehen werden, was Sie von so ziemlich jedem Compiler erwarten, den Sie finden können. Während Sie dieses Verhalten normalerweise sehen, ist es wahrscheinlich keine gute Idee, sich darauf zu verlassen.
sblom
6
Es ist nicht undefiniert (siehe §4.7 / 2 ), aber die Darstellung (z. B. 2s-Komplement) ist nicht durch den Standard vorgeschrieben.
Georg Fritzsche
@ gf (et al. unten), cool. Es sieht so aus, als ob das Verhalten tatsächlich explizit so definiert ist, wie Sie es erwartet haben, @viswanathan.
sblom
3
Die zweite Zeile entspricht nVal = (unsigned int) -5;. Die Besetzung von -5to unsigned intist in 6.3.1.3 definiert . Die Darstellung im 2s-Komplement ist vom Standard nicht vorgeschrieben, aber der Algorithmus zum Konvertieren in vorzeichenlose Werte lautet: "Der Wert wird konvertiert, indem wiederholt mehr als der Maximalwert addiert oder subtrahiert wird, der im neuen Typ dargestellt werden kann, bis der Wert im Bereich liegt des neuen Typs. "
Pascal Cuoq
1
@Pascal: Sie scheinen sich auf C99 zu beziehen, aber die Frage ist mit C ++ gekennzeichnet.
Georg Fritzsche

Antworten:

67

Für die offizielle Antwort - Abschnitt 4.7 Conv.integral

"Wenn der Zieltyp ohne Vorzeichen ist, ist der resultierende Wert die am wenigsten vorzeichenlose Ganzzahl, die mit der Quell-Ganzzahl kongruent ist (Modulo 2 n, wobei ndie Anzahl der Bits zur Darstellung des vorzeichenlosen Typs verwendet wird). [Hinweis: In einer Zweierkomplementdarstellung diese Konvertierung ist konzeptionell und es gibt keine Änderung im Bitmuster (wenn es keine Kürzung gibt). - Endnote]

Dies bedeutet im Wesentlichen, dass sich die Konvertierung in vorzeichenloses Verhalten so verhalten muss, als wäre es Two's Complement, wenn die zugrunde liegende Architektur in einer Methode gespeichert wird, die nicht Two's Complement ist (wie Signed Magnitude oder One's Complement).

Dennis Zickefoose
quelle
37
Was bedeutet die am wenigsten vorzeichenlose Ganzzahl, die zur Quell-Ganzzahl kongruent ist ?
David Rodríguez - Dribeas
11
@ DavidRodríguez-dribeas Als Beispiel sind 5 und 3 "kongruente Mod 2", da 5% 2 und 3% 2 beide 1 sind.
JoeQuery
Auf welche Versionen des C ++ - Standards bezieht es sich? Alle?
Alexey Kruglov
36

Es wird dem vorzeichenlosen int das Bitmuster zuweisen, das -5 (im Zweierkomplement) darstellt. Welches wird ein großer vorzeichenloser Wert sein. Für 32-Bit-Ints ist dies 2 ^ 32 - 5 oder 4294967291

Jasmeet
quelle
2
Bits haben nichts damit zu tun.
GManNickG
1
@ BenVoigt: Fair genug, ich meinte, es hat nichts damit zu tun, wie Bits interpretiert werden. (Das heißt, die "Bits" im zitierten Teil sind nur Abkürzungen für ceil(log_2(x)).)
GManNickG
1
@GManNickG Bits (wie in, gehört zum Bit)? 2's Kompliment (das ist sehr nett von dir) ? GAAAAAAAAAAAAAH!
NullUserException
1
@NullUserException: Haha, ich weiß. "* 'S" anstelle von "* s" zu schreiben, ist eine schreckliche Angewohnheit, die ich seit einiger Zeit habe. Kompliment statt Kompliment, das ist nur reine Dummheit. :)
GManNickG
Einfachheit ist der Schlüssel. Diese Antwort hat das. (2 ^ 32 - 5) erklärt dieses Verhalten besser als das Zitieren der Dokumentation.
Redhart
4

Es wird als positive Ganzzahl des Werts der maximalen Ganzzahl ohne Vorzeichen - 4 angezeigt (der Wert hängt von der Computerarchitektur und dem Compiler ab).

Übrigens können
Sie dies überprüfen, indem Sie ein einfaches C ++ - Programm vom Typ "Hallo Welt" schreiben und sich selbst davon überzeugen

Dror Helfer
quelle
Ich habe es geschrieben und überprüft, deshalb habe ich die Frage gestellt, aber ich wusste nicht, wie der Compiler zu diesem positiven Wert gekommen ist. Danke
ckv
6
Leider ist es in C ++ nicht immer eine gute Idee, Programme zum Testen des Verhaltens zu schreiben. Wenn man beispielsweise versucht, zu testen, was im Falle eines signierten Überlaufs passiert , führt dies zu einem undefinierten Verhalten, das nicht auf jedem Computer / Compiler gleich ist.
Ben Jones
4

Sie haben Recht, die vorzeichenbehaftete Ganzzahl wird in der Komplementform von 2 und die vorzeichenlose Ganzzahl in der vorzeichenlosen Binärdarstellung gespeichert . C (und C ++) unterscheiden nicht zwischen den beiden, daher ist der Wert, den Sie erhalten, einfach der vorzeichenlose Binärwert der komplementären Binärdarstellung der 2.

Perimosocordiae
quelle
16
Es darf nicht im Kompliment von 2 gespeichert werden.
GManNickG
Was bedeutet es, wenn etwas "in 2er gespeichert" ist? @ GManNickG
JeremyF
4
@JeremyF: Nicht "2", "2 Kompliment". Es ist ein Google-fähiger Begriff und eine Möglichkeit, vorzeichenbehaftete Ganzzahlen darzustellen.
GManNickG
2

Ja, du hast recht. Der tatsächlich zugewiesene Wert entspricht etwa allen gesetzten Bits mit Ausnahme des dritten. -1 sind alle gesetzten Bits (hex: 0xFFFFFFFF), -2 sind alle Bits außer dem ersten und so weiter. Was Sie sehen würden, ist wahrscheinlich der Hex-Wert 0xFFFFFFFB, der in Dezimalzahl 4294967291 entspricht.

Martin
quelle
3
Bits haben nichts damit zu tun, eine ganzzahlige Darstellung ist nicht angegeben.
GManNickG
2
Ihre Antwort ist richtig, streng, auf den Punkt und etwas, das ich im Unterricht niemals verwenden würde.
Martin
siehe meine Antwort für das 2er-Komplement von -5. Ich glaube nicht, dass Sie die Binärwerte hier richtig berechnet haben.
Cynistersix
0

Wenn Sie einer vorzeichenlosen Variablen einen negativen Wert zuweisen, wird sie mit der Zweierkomplementmethode verarbeitet. Bei dieser Methode werden alle Nullen auf 1 und alle Einsen auf Nullen umgedreht und anschließend 1 hinzugefügt. In Ihrem Fall handelt es sich um int mit 4 Byte (32 Bit), sodass versucht wird, die 2-Komplement-Methode für die 32-Bit-Zahl zu verwenden, wodurch das höhere Bit umgedreht wird. Zum Beispiel:

┌─[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
Zafeer
quelle