Почему здесь uint16_t имеет значение?

volatile uint16_t r;
unsigned char poly = 0x07;
unsigned char c = 0;

r = (c << 8) ^ poly;

Когда код скомпилирован с gcc в Linux, r есть 7.
Когда тот же код скомпилирован Microchip C18, r - 0.
Почему?

Если я изменил его на:

volatile uint16_t r;
uint16_t poly = 0x07;
uint16_t c = 0;

r = (c << 8) ^ poly;

r также становится 7 в C18.

В руководстве C18 есть раздел о продвижении по целому ряду, но я не думаю, что он имеет какое-то отношение к моему вопросу. Во всяком случае, вот оно:

ISO обязывает, чтобы вся арифметика выполнялась с точностью до или более. По умолчанию MPLAB C18 будет выполнять арифметика с размером наибольшего операнд, даже если оба операнда меньше, чем int. Утвержденный ISO поведение может быть введено через -Oi командной строки.

Ответы

Ответ 1

Так как c << 8 undefined в этом компиляторе, результат xor не может быть предсказан. Результатом может быть все, что выбирает компилятор.

См. Что должен знать каждый программист C о undefined Поведение для ознакомления с поведением undefined, особенно в разделе "Негабаритные суммы сдвига" ".

Ответ 2

c < 8 с c a char в основном передает все биты в забвение. Как указано в документе, оба c и 8 соответствуют char, поэтому все делается с помощью char.

c < 8UL может изменить сделку.