Zeichen und die üblichen arithmetischen Umrechnungsregeln

Ich weiß, dass diese Frage millionenfach gestellt und anscheinend beantwortet wurde, aber ich kann die Antworten nicht mit meinen eigenen Erfahrungen vergleichen.

Die C-Norm legt fest, dass für die Addition "beide Operanden einen arithmetischen Typ haben sollen" (6.5.6.1). Arithemitc-Typen umfassen Integer- und Floating-Typen (6.2.5.18) und Integer-Typen sind char, short, int, long und long long, die als vorzeichenbehaftete und vorzeichenlose Typen (6.2.5.4 und 6.2.5.6) existieren. Gemäß den Regeln für die übliche arithmetische Konvertierung "Wenn beide Operanden den gleichen Typ haben, ist keine weitere Konvertierung erforderlich." So weit, ist es gut.

Ich habe verstanden, wie hier aus "The C Book" hervorgeht, dass "[n] o-Arithmetik von C mit einer Genauigkeit ausgeführt wird, die kürzer als int ist", wobei eine ganzzahlige Promotion angewendet wird. Ich kann in der Norm keinen Hinweis darauf finden, da ich dies anscheinend mehrfach gesehen habe.

Da vorzeichenloses Zeichen ein arithmetischer Typ ist und die Regeln für die gewöhnliche arithmetische Konvertierung besagen, dass Operanden desselben Typs keine Konvertierung benötigen, warum ist eine integrale Heraufstufung erforderlich?

Ich habe dies mit zwei verschiedenen Compilern getestet. Ich habe ein einfaches Programm geschrieben, das zusätzlich char enthält:

unsigned char a = 1;
unsigned char b = 2;
unsigned char c = a + b;

Die Zielplattform ist ein Atmel Mega8 uC mit einer 8-Bit-Architektur. Eine Ganzzahladdition würde daher die Verwendung von zwei Registern erfordern, wenn die Operanden einer integralen Heraufstufung unterzogen werden sollten.

Wenn Sie dies mit dem imagecraft avr-Compiler ohne Optimierung und mit aktivierten strengen und ANSI C-Portabilitätsoptionen kompilieren, erhalten Sie den folgenden Assemblycode:

mov R16, R20
add R16, R18

Verwendung von avr-gcc (mir ist kein ANSI-Schalter bekannt, der gccs -strict ähnelt):

$ avr-gcc -O0 -mmcu=atmega8 -S -c main.c

Die resultierende Baugruppe:

ldd r25,Y+1
ldd r24,Y+2
add r24,r25
std Y+3,r24

Der resultierende Code arbeitet in beiden Fällen mit einem einzelnen Byte. Ich erhalte ähnliche Ergebnisse für bitweise | und & und logisch || und &&. Bedeutet dies dann, dass Standard arithmetische Operationen mit Zeichentypen ohne integrale Beförderung erlaubt, oder bedeutet dies einfach, dass diese Compiler nicht standardkonform sind?

Zusätzlich:

Es stellt sich heraus, dass alles von dem Typ abhängt, in dem das Ergebnis gespeichert ist. Das oben gezeigte Beispiel ist nur dann wahr, wenn das Ergebnis in einem Zeichen gespeichert ist, und es hängt nicht vom Ergebnis der Addition ab. Wenn Sie a auf 0xFF und b auf 1 setzen, wird genau derselbe Assembly-Code erstellt.

Wenn der Typ von c in unsigned int geändert wird, sieht die resultierende Assembly folgendermaßen aus:

mov R2,R20
clr R3
mov R16,R18 
clr R17
add R16,R2 
adc R17,R3 

Selbst in dem Fall, in dem das Ergebnis in einem einzelnen Byte gehalten werden kann, d. H. A = 1 und b = 2.

Antworten auf die Frage(5)

Ihre Antwort auf die Frage