2016-04-11 8 views
2

a + b Überläufe 255 zurück zu 4, wie ich erwarten würde, dann c/2 gibt 2, wie ich es erwarte. Warum aber ist das letzte Beispiel bei der Auswertung der beiden gleichen Schritte nicht übergelaufen?C überläuft innerhalb einer Gleichung?

Ich vermute, die internen Berechnung Werte werden mit mehr Bits gespeichert, dann nur auf 8 Bit gekürzt, wenn Sie die Zuweisung tun. In diesem Fall, wo ist das Limit, muss es irgendwann überlaufen?

uint8_t a = 250; 
uint8_t b = 10; 
uint8_t c = (a + b); 
uint8_t d = c/2; 
uint8_t e = (a + b)/2; 

std::cout << unsigned(c) << ", " << unsigned(d) << ", " << unsigned(e) << "\n"; 

4, 2, 130

+0

Vielleicht finden Sie [** diese **] (http://ideone.com/WBVJ8t) interessant. Beachten Sie den abgeleiteten Parametertyp. – WhozCraig

Antwort

2

Es heißt integrale Förderung. Die Operationen selbst werden im nativen Integer-Typ Ihrer CPU ausgeführt, int, der Zahlen größer als 255 enthalten kann. Im Fall a+b muss das Ergebnis in einem uint8_t gespeichert werden, und dort wird die Kürzung vorgenommen. Im letzten Fall gibt es zuerst eine Division, die als int ausgeführt wird, und das Ergebnis kann perfekt in einem uint8_t gespeichert werden.

+0

zu werden. Also würde ich ein anderes Ergebnis auf verschiedenen CPUs abhängig von ihrer nativen int Größe erhalten? – trapper

+0

Ja, aber 'int' muss immer mindestens 32767 halten können, also in diesem Fall mit 255 immer das gleiche Ergebnis. – atturri

+0

@trapper Beachten Sie außerdem, dass das Umbrechen bei Überlauf nur für * unsigned * Ganzzahlen definiert ist. Überlaufende * signed * Ganzzahlen sind undefiniertes Verhalten. –

0

a+b gibt Wert 260, der zu jedem uint8_t Typ nicht zugeordnet ist, so dass Sie im letzten Fall gut sind. Nur wenn Sie einen Wert größer als 255 an uint8_t übergeben, dann ist ein Überlauf vorhanden.

+0

'a + b' ist 260 was zu 4 rollt. Die Frage ist warum passiert das nicht mit' (a + b)/2' – trapper

+0

@trapper Yeah redigierte meine Antwort. 'a + b = 260', aber 260 ist keinem' uin8_t' zugewiesen, der abgeschnitten werden soll/übergelaufen wird, um 4 – Gopi

0

Im folgenden (a + b) nicht überflutet nicht, der Compiler a und b als Integer-Typ erkennt so Additionsergebnisse in einem Integer-Typ, das Ergebnis dieses Ausdrucks nicht durch die Größe der Begriffe oder Faktoren im Ausdruck beschränkt.

Nehmen wir an, der Typ einer Variablen wie a oder b in diesem Fall beschränkt das Ergebnis auf nur diesen Typ. Wenn möglich, wäre es fast unmöglich, eine solche Sprache zu verwenden. Stellen Sie sich vor fünf Variablen, dass, wenn kein Typ Betrachtung ist sie also, dies zu 500 gemacht Summe ..

uint8_t a = 98; 
uint8_t b = 99; 
uint8_t c = 100; 
uint8_t d = 101; 
uint8_t e = 102; 

Die Summe der obigen Variablen == 500. Nun ... in denen nach dem Ergebnis eines Ausdrucks kann das nicht überschreiten Größe einer der Begriffe ...

int incorrect = (a + b + c + d + e); 

in diesem Fall (a + b + c) == 41 dann (41 + d + e) == 244. Dies ist eine unsinnige Antwort .. Die Alternative, dass die meisten Menschen also erkennen

(98 + 99 + 100 + 101 + 102) == 500; 

Dies ist ein Grund, warum Typumwandlung existiert.

Zwischenergebnisse in Ausdrücken sollten nicht durch die Ausdrücke oder Faktoren im Ausdruck eingeschränkt sein, sondern durch den resultierenden Typ, dh den Lvalue.

0

@atturri ist korrekt. hier ist das, was in x86 Maschinensprache auf Ihre Variablen geschehen:

REP STOS DWORD PTR ES:[EDI] 
MOV BYTE PTR SS:[a],0FA 
MOV BYTE PTR SS:[b],0A 
MOVZX EAX,BYTE PTR SS:[a] ; promotion to 32bit integer 
MOVZX ECX,BYTE PTR SS:[b] ; promotion to 32bit integer 
ADD EAX,ECX 
MOV BYTE PTR SS:[c],AL ; ; demotion to 8bit integer 
MOVZX EAX,BYTE PTR SS:[c] 
CDQ 
SUB EAX,EDX 
SAR EAX,1 
MOV BYTE PTR SS:[d],AL 
MOVZX EAX,BYTE PTR SS:[a] 
MOVZX ECX,BYTE PTR SS:[b] 
ADD EAX,ECX 
CDQ 
SUB EAX,EDX 
SAR EAX,1 
MOV BYTE PTR SS:[e],AL