char y las reglas de conversión aritméticas habituales

Sé que esta pregunta ha sido formulada y aparentemente ha sido contestada miles de veces, pero parece que no puedo hacer coincidir las respuestas con mi propia experiencia.

El estándar C especifica que para la adición "ambos operandos tendrán un tipo aritmético" (6.5.6.1). Los tipos Arithemitc cubren los tipos enteros y flotantes (6.2.5.18) y, finalmente, los tipos enteros son char, short, int, long y long long que existen como tipos con signo y sin signo (6.2.5.4 y 6.2.5.6). De acuerdo con las reglas para la conversión aritmética habitual "Si ambos operandos tienen el mismo tipo, no se necesita más conversión". Hasta ahora tan bueno.

Según lo ejemplificado aquí en "El libro C", he entendido que "n la aritmética no se realiza mediante C con una precisión más corta que int", que es donde se aplica la promoción integral. No puedo encontrar ninguna referencia a esto en el estándar porque parece que lo he visto varias veces.

Dado que el carácter unsigned char es un tipo aritmético y las reglas para la conversión aritmética habitual indican que los operandos del mismo tipo no necesitan conversión, ¿por qué la necesidad de una promoción integral?

He probado esto utilizando dos compiladores diferentes. Escribí un programa simple que hace además de char:

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

La plataforma de destino es un Atmel Mega8 uC que utiliza una arquitectura de 8 bits. Por lo tanto, una adición de enteros requeriría el uso de dos registros si los operandos deberían estar sujetos a una promoción integral.

Al compilar esto con el compilador avr de imagecraft sin optimización y con las opciones de portabilidad ANSI C estrictas habilitadas, se obtiene este código de ensamblaje:

mov R16, R20
add R16, R18

Uso de avr-gcc (no tengo conocimiento de un interruptor ANSI similar al de gcc -strict):

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

El montaje resultante:

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

El código resultante en ambos casos opera en un solo byte. Obtengo resultados similares para bitwise | y & y lógico || y &&. ¿Esto significa que el estándar permite operaciones aritméticas en tipos de caracteres sin promoción integral o simplemente significa que estos compiladores no cumplen con el estándar?

Adicional:

Resulta que todo depende del tipo en el que se almacena el resultado. El ejemplo que se muestra arriba solo es cierto cuando el resultado se almacena en un char, y no depende del resultado de la adición. Establecer a 0xFF y b a 1 produce exactamente el mismo código de ensamblaje.

Si el tipo de c se cambia a unsigned int, el ensamblaje resultante tiene este aspecto:

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

Incluso en el caso de que el resultado se pueda mantener en un solo byte, es decir, a = 1 y b = 2.

Respuestas a la pregunta(5)

Su respuesta a la pregunta