char i zwykłe reguły konwersji arytmetycznej

Wiem, że to pytanie zostało zadane i na pozór odpowiedziało mi miliony razy, ale wydaje mi się, że nie pasuję do odpowiedzi na moje własne doświadczenia.

Standard C określa, że ​​dla dodania „oba operandy będą miały typ arytmetyczny” (6.5.6.1). Typy Arithemitc obejmują typy całkowite i zmienne (6.2.5.18), a na końcu typy całkowite są znakami char, short, int, long and long long, które występują jako typy podpisane i niepodpisane (6.2.5.4 i 6.2.5.6). Zgodnie z zasadami zwykłej konwersji arytmetycznej „Jeśli oba operandy mają ten sam typ, nie jest potrzebna dalsza konwersja”. Jak na razie dobrze.

Zrozumiałem, jak to ilustruje tutaj „The C Book”, że „[n] o arytmetyka jest wykonywana przez C z dokładnością krótszą niż int”, co oznacza, że ​​stosowana jest integralna promocja. Nie mogę znaleźć żadnego odniesienia do tego w standardzie, wydaje mi się, że widziałem to już wiele razy.

Ponieważ znak unsigned char jest typem arytmetycznym, a reguły zwykłej konwersji arytmetycznej stanowią, że operandy tego samego typu nie wymagają konwersji, dlaczego potrzebna jest integralna promocja?

Przetestowałem to za pomocą dwóch różnych kompilatorów. Napisałem prosty program, który dodaje dodatek char:

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

Platformą docelową jest Mega8 uC Atmel z 8-bitową architekturą. Dodanie liczby całkowitej wymagałoby zatem użycia dwóch rejestrów, jeśli operandy powinny podlegać integralnej promocji.

Kompilacja tego przy użyciu kompilatora imagecraft avr bez optymalizacji i przy włączonych opcjach ścisłej i ANSI C daje ten kod zespołu:

mov R16, R20
add R16, R18

Używanie avr-gcc (nie znam przełącznika ANSI podobnego do gcc -strict):

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

Wynikowy zespół:

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

Wynikowy kod w obu przypadkach działa na pojedynczym bajcie. Otrzymuję podobne wyniki dla bitwise | i & i logiczny || i &&. Czy to oznacza, że ​​ten standard pozwala na operacje arytmetyczne na typach znaków bez integralnej promocji, czy też po prostu oznacza, że ​​te kompilatory nie są standardowe?

Dodatkowy:

Okazuje się, że wszystko zależy od typu przechowywanego wyniku. Przykład pokazany powyżej jest prawdziwy tylko wtedy, gdy wynik jest przechowywany w znaku i nie zależy od wyniku dodania. Ustawienie a na 0xFF i b na 1 daje dokładnie ten sam kod zespołu.

Jeśli typ c zostanie zmieniony na niepodpisany, wynikowy zespół wygląda tak:

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

Nawet w przypadku, gdy wynik może być utrzymywany w pojedynczym bajcie, tj. A = 1 ib = 2.

questionAnswers(5)

yourAnswerToTheQuestion