Warum unterscheidet es sich zwischen -2147483648 und (int) -2147483648

8

Wenn ich den folgenden Code unter Windows7 x64 ausführe, kompiliert mit GCC von MinGW, scheint das Ergebnis zu unterlaufen:

%Vor%

aber wenn ich es einer Integer-Variablen zugewiesen habe, oder einfach einfach in den int-Typ umwandeln:

%Vor%

Also, was ist falsch an der vorherigen Version meines Codes? Ist es nicht der Typ Int? oder was die Untergrenze der Integer ist genau? Vielen Dank.

    
lichenbo 27.09.2012, 11:51
quelle

4 Antworten

11

2147483648 passt nicht in ein int oder ein long auf Ihrem System, daher wird es als Konstante vom Typ unsigned long behandelt. (Edit: wie ouah in den Kommentaren darauf hingewiesen hat, ist es ein undefiniertes Verhalten in Standard C ++, aber Ihr Compiler akzeptiert es als Erweiterung.) Es ist möglich, einen vorzeichenlosen Integer-Wert zu negieren, aber einen anderen vorzeichenlosen Integer-Wert, niemals eine negative Zahl. Das Negieren von 2147483648UL erzeugt 2147483648UL (vorausgesetzt, dass, wie bei Ihrem System, der unsigned long ein 32-Bit-Typ ist).

Wenn Sie das auf int umleiten, erhalten Sie ein implementationsdefiniertes Ergebnis, das Sie normalerweise sehen, aber nicht unbedingt. Sie können das gewünschte Ergebnis ohne jegliche Konvertierung erhalten, indem Sie -2147483647 - 1 schreiben.

    
hvd 27.09.2012, 11:57
quelle
3
  

Was stimmt also nicht mit der vorherigen Version meines Codes?

Vermutlich verwenden Sie einen Pre-2011-Compiler, und auf Ihrem System hat long 32 Bits. Der Wert (-2 31 ) stimmt nicht garantiert mit long überein, daher könnte er überlaufen. Das gibt undefiniertes Verhalten, so dass Sie alles sehen können.

Die wahrscheinlichste Erklärung für den besonderen Wert, den Sie sehen (2 31 ), besteht darin, dass Ihr Compiler bei Fehlen eines definierten Verhaltens in C ++ die alten C90-Regeln verwendet und den Wert in konvertiert unsigned long .

  

Ist es nicht der Typ int?

Vor 2011 war es int , wenn der Wert durch int dargestellt werden kann, andernfalls long , mit undefiniertem Verhalten, wenn das nicht ausreicht. C ++ 11 fügt den long long -Typ hinzu und erlaubt, dass dieser für Integer-Literale verwendet wird, wenn long nicht groß genug ist.

  

oder was die untere Grenze der Integer ist genau?

Vorzeichenbehaftete ganzzahlige Typen mit N Bits haben einen Bereich von mindestens -2 (N-1) +1 bis 2 <(N-1) -1. Ihr Wert ist -2 31 , was gerade außerhalb des Bereichs für einen 32-Bit-Typ mit Vorzeichen liegt.

Die Sprache gibt nicht die genaue Größe der Integer-Typen an; nur dass int mindestens 16 Bits haben muss, long mindestens 32 und (seit 2011) long long mindestens 64.

    
Mike Seymour 27.09.2012 12:32
quelle
2

Zunächst ist es wichtig zu verstehen, dass es keine negativen Ganzzahl-Literale gibt.

Andere haben erklärt, warum sich der spezielle Compiler des OP so verhält wie er. Aber für den Datensatz, das ist, was der Compiler tun sollte, zwischen den Zeilen, auf einem 32-Bit-System:

  • Sie haben die Nummer 2147483648, die nicht in ein 32-Bit-signiertes int des Zweierkomplement-Formats passen kann.
  • Da es sich um eine Dezimalzahl handelt (ohne ein U-, L- oder ähnliches Suffix), prüft der Compiler seine interne Typentabelle (1) auf eine solche Integer-Konstante. Es funktioniert wie folgt: Versuchen Sie, es in eine int zu passen, wenn es nicht passt, versuchen Sie long , wenn es auch dort nicht passt, versuchen Sie long long , wenn es nicht dort passt Entweder haben wir undefiniertes Verhalten. Ein C- oder C ++ - Compiler, der dem neuesten Standard folgt, versucht nicht , ihn in vorzeichenlose Typen einzufügen.
  • In diesem speziellen Fall passt die Zahl nicht in ein int oder in ein long , daher entscheidet sich der Compiler dafür, ein long long als Typ für das Literal zu verwenden.
  • Sie verwenden dann den unären Minus-Operator für dieses Literal und enden mit der Nummer -2147483648. Ironischerweise würde dies in ein vorzeichenbehaftetes int des Zweierkomplement-Formats passen, aber es ist zu spät, um den Typ zu ändern, der Compiler hat bereits long long als Typ ausgewählt.

(1) Diese "interne Tabelle" sieht anders aus, wenn Sie ein unsigniertes Suffix haben oder wenn Sie ein Hexadezimalformat usw. haben. Wenn ein Suffix ohne Vorzeichen vorhanden ist, wird nur geprüft, ob die Zahl in vorzeichenlose Zahlen passt. Wenn es eine hexadezimale Schreibweise gibt (aber kein Suffix), wird int geprüft, dann wird unsigned int, dann lang usw.

    
Lundin 27.09.2012 13:10
quelle
0

Tatsächlich habe ich eine Erklärung aus einer PDF-Datei von CS: APP gefunden, die perfekt die Lösung liefert, die Sie von hier herunterladen können. Ссылка

    
lichenbo 02.10.2012 04:42
quelle

Tags und Links