Почему 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 требует, чтобы все арифметические операции выполнялись с точностью int или выше. По умолчанию MPLAB C18 будет выполнять арифметические операции с размером наибольшего операнда, даже если оба операнда меньше целого числа. Поведение, требуемое ISO, можно установить с помощью параметра командной строки -Oi.


person AndreKR    schedule 23.05.2011    source источник
comment
Что происходит на C18 для r = c ^ poly; или r = (0) ^ poly;? Вы пробовали переключатель -Oi, как это предлагается в руководстве?   -  person Adam    schedule 23.05.2011
comment
В обоих случаях это по-прежнему 0, но с включенной опцией -Oi это 7.   -  person AndreKR    schedule 23.05.2011
comment
Затем используйте -Oi и жалуйтесь поставщику вашего компилятора, что его компилятор не работает по умолчанию...   -  person R.. GitHub STOP HELPING ICE    schedule 23.05.2011
comment
Кстати, с r = (c << 7) ^ poly r равно 7.   -  person AndreKR    schedule 23.05.2011


Ответы (2)


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

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

person ergosys    schedule 23.05.2011
comment
c<<8 не является неопределенным ни в одной реализации C. - person R.. GitHub STOP HELPING ICE; 23.05.2011
comment
@R, стандарт C будет продвигаться до int. Этот компилятор, по-видимому, не так, как указано в ОП. Таким образом, операция, по сути, представляет собой негабаритную смену, AFAICT. - person ergosys; 23.05.2011
comment
Я открыл билет с Microchip для подтверждения. - person AndreKR; 23.05.2011
comment
Microchip подтвердил, что приведение c к int необходимо, так что ответ кажется правильным. - person AndreKR; 05.07.2011

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

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

person Joel Falcou    schedule 23.05.2011
comment
Это объясняет, что происходит с c, если какой-либо из битов был установлен, но не объясняет, почему также исчезает фрагмент ^ poly. - person viraptor; 23.05.2011
comment
На самом деле, в стандарте также говорится, что сдвиг целого числа размером n бит на n является неопределенным поведением, поэтому кто знает, что делает сдвиг символа на 8 в этом компиляторе? (примечание: в стандартном компиляторе c<<8 определяется в силу повышения до int, которое этот компилятор удаляет) - person Pascal Cuoq; 23.05.2011
comment
О, интересно. Это объясняет, почему результаты, которые я получаю, не определены. Мне даже удалось получить 0x62 вместо 0x00, а в другом варианте я получил дизассемблирование, которое полностью игнорировало эту строку. Это ответ, я думаю. - person AndreKR; 23.05.2011