2014-03-31 5 views
6

ich lerne derzeit C-Programm aber stieß ich auf einige seltsame Verhalten ich erwartet hatte ein Ergebnis, aber zwei Ergebnisse ist wie diese könnte Wie können sowohl (i + 1) <ii als auch (i + 1)> ii beide wahr sein?

$ ./a.out 
yes1 0x80000000 
yes3 0x80000000 

gedruckt, wie das möglich?
Ich kann das Ergebnis nicht verstehen.

OS : x86_64 Ubuntu Linux 
C compiler : gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 

gcc -O2 weird.c 

#include <stdio.h> 

int main() { 

    int i = 0x7fffffff; 
    int ii = 0x0000000f; 

    if ((i + 1) < ii) 
     printf ("yes1 %#x\n", i + 1); 

    if ((i + 1) == ii) 
     printf ("yes2 %#x\n", i + 1); 

    if ((i + 1) > ii) 
     printf ("yes3 %#x\n", i + 1); 

    return 0; 
} 
+1

0x7fffffff + 1 = 0x80000000 –

+0

gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7 .2 macht es richtig (auf einem 32-Bit-System) – fritzone

+0

Es wurde entfernt, aber Sie hatten ursprünglich das C++ - Tag, kümmern Sie sich überhaupt um C++? –

Antwort

7

In Ihrem Fall (i + 1) über den Bereich der überquell Ganzzahlvariable.

Die Wahrheit ist, dass der Überlauf auf eine vorzeichenbehaftete int-Variable ein undefiniertes Verhalten im ANSI-Standard ist, so streng genommen kann es zu jedem Ergebnis führen. Ihr Compiler könnte dem Standard entsprechen, aber jeder mit gutem Computerverständnis würde erwarten, dass die Variable auf negative Werte überläuft, einfach weil Computerregister nicht vorzeichenbehaftete/vorzeichenlose Bereiche unterscheiden. Hier

ist, was ANSI-Standard sagt auf Undefined behavior (unter anderen Fällen):

Das Verhalten in den folgenden Umständen ist nicht definiert:

Eine arithmetische Operation ist ungültig (wie Division oder Modul von 0) oder erzeugt ein Ergebnis, das nicht im bereitgestellten Raum dargestellt werden kann (z. B. Überlauf oder Unterlauf) ($ 3,3).

Auf der anderen Seite ist dies für unsigned Typen nicht gültig:

Eine Berechnung unsigned Operanden beinhalten, können nie Überlauf, weil ein Ergebnis, das durch die resultierende unsigned integer Typ nicht dargestellt werden kann, ist, reduziert modulo die Zahl, die ist, größer als der größte Wert, der durch den resultierenden unsigned Integer-Typ dargestellt werden kann.

Auch hier ist der entsprechende Teil aus genanntem Abschnitt ($ 3.3 Expressions):

Wenn eine Ausnahme während der Auswertung eines Ausdrucks auftritt (die ist, wenn das Ergebnis nicht mathematisch definiert ist oder nicht darstellbar), das Verhalten ist nicht definiert.

+0

Man könnte '-fwrapv' einstellen, wodurch der Überlauf als Umbruch definiert wird. – Hasturkun

+0

Vermutlich würde "-fwrapv" die in meiner Antwort erwähnte problematische Optimierung deaktivieren. – keshlam

+0

Es sieht so aus, als ob Sie den Anhang, der nicht normativ ist, zitieren, obwohl ich nicht finden kann, dass die Formulierung in entweder Entwurf C99 oder Entwurf C11 Sie zitiert C89? ANSI ist vage, heute würde ich das als C11 bezeichnen. –

3

In allen Fällen, in Ihrem Code i+1 produziert Signed Integer Überlauf die undefined behavior ist, was bedeutet, das Programm unvorhersehbar verhalten kann. Wir können sehen, sie aus dem draft C99 standard Abschnitt 6.5Expressions Absatz , die sagt (Hervorhebung von mir) nicht definiert ist:

Wenn eine Ausnahmebedingung auftritt, während der Auswertung eines Ausdrucks (das heißt, wenn die Ergebnis ist nicht mathematisch definiert oder nicht im Bereich der darstellbaren Werte für seine Typ), das Verhalten ist undefiniert.

Es ist der gleiche Abschnitt in der Entwurf C11 Standard auch.

Eine Möglichkeit, diese clangs santizer suite Verwendung clangs -fsanitize=undefined Option sein, die einen Teil gefangen hätte ist, dass wir die folgenden Laufzeitfehler erhalten:

runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 
2

Ich glaube, Sie in einen Optimierer Fall laufen lassen, wo der Compiler sagt, dass ganze Zahlen, so kann x+1>y effizienter als x>=y berechnet werden ... und leider während das ist im Allgemeinen wahr, und ist immer wahr für Werte ohne Vorzeichen , dieser eine spezielle Fall, bei dem x + 1 umschlägt, um negativ zu sein, bricht die Annahme.

Da jedoch ein int-Überlauf uns in den Bereich des undefinierten Verhaltens bringt (siehe @ Marian's Antwort), ist dies nicht inkorrekt. Nur überraschend.

(Gedanken über meine Antwort zu löschen, aber da es zeigt, wie beide Tests wahr sein könnte ich denke, es ist wert zu halten ist.)

+0

Dies ist kein Compilerfehler. Vorübergehender Ganzzahlüberlauf ist ein nicht definiertes Verhalten. – Hasturkun

+0

Danke; klar abgeklärt. – keshlam

+0

Die spezifische Optimierung im Spiel ist hier "-fstrict-overflow". Unter "-O2" aktiviert gcc die "-fstrict-overflow" -Optimierung, mit der davon ausgegangen werden kann, dass der signierte Überlauf nicht definiert ist. Die Verwendung von '-fwrapv' lässt den Compiler davon ausgehen, dass der Überlauf stattdessen einen Wraparound verursacht. In der C99-Spezifikation, Abschnitt 3.4.3, sei als Beispiel erwähnt, dass das Beispiel für die Definition von undefiniertem Verhalten besagt: "Ein Beispiel für undefiniertes Verhalten ist das Verhalten bei Integer-Überlauf" – Hasturkun

Verwandte Themen