символ и обычные правила арифметического преобразования

Я знаю, что на этот вопрос задавали и, казалось бы, отвечали тысячи раз, но я не могу сопоставить ответы с моим собственным опытом.

Стандарт C устанавливает, что для добавления «оба операнда должны иметь арифметический тип» (6.5.6.1). Типы Arithemitc охватывают целочисленные и плавающие типы (6.2.5.18), и, наконец, целочисленные типы - это char, short, int, long и long long, которые существуют как типы со знаком и без знака (6.2.5.4 и 6.2.5.6). Согласно правилам обычного арифметического преобразования «Если оба операнда имеют одинаковый тип, дальнейшее преобразование не требуется». Все идет нормально.

Как я понял из «Книги C», я понял, что «[n] o арифметика выполняется C с точностью короче, чем int», где применяется интегральное продвижение. Я не могу найти ссылку на это в стандарте, я, кажется, видел это много раз.

Поскольку unsigned char является арифметическим типом, а правила обычного арифметического преобразования гласят, что операнды одного и того же типа не нуждаются в преобразовании, зачем нужна целочисленное продвижение?

Я проверил это с помощью двух разных компиляторов. Я написал простую программу, которая делает сложение символов:

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

Целевая платформа - Atmel Mega8 uC, использующая 8-битную архитектуру. Следовательно, целочисленное сложение потребует использования двух регистров, если операнды должны подвергаться интегральному продвижению.

Компиляция этого с использованием компилятора imagecraft avr без оптимизации и с включенными строгими параметрами ANSI C и переносимостью дает следующий код сборки:

mov R16, R20
add R16, R18

Использование avr-gcc (я не знаю о параметре ANSI, похожем на gcc -strict):

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

Получившаяся сборка:

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

Результирующий код в обоих случаях работает с одним байтом. Я получаю аналогичные результаты для побитового | и & и логично || а также &&. Значит ли это, что стандарт разрешает арифметические операции над типами символов без интегрального продвижения или просто означает, что эти компиляторы не соответствуют стандарту?

Дополнительно:

Оказывается, все зависит от типа, в котором хранится результат. Приведенный выше пример верен только в том случае, если результат хранится в символе и не зависит от результата сложения. Установка a в 0xFF и b в 1 дает точно такой же код сборки.

Если тип c изменяется на unsigned int, результирующая сборка выглядит так:

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

Даже в случае, когда результат может храниться в одном байте, то есть a = 1 и b = 2.

Ответы на вопрос(5)

Ваш ответ на вопрос