LINUX.ORG.RU

Поясните про сдвиг в C

 ,


1

2

Корректен ли такой код, если нужно склеить 2 байта:

unsigned char a = 0xAA;
unsigned char b = 0xFF;
unsigned short c = (a<<8)|b;
Получаю 0xAAFF. Так и должно быть или это UB? Почему результат (a<<8) не 0?
Стандарт:

3 The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative ori s greater than or equal to the width of the promoted left operand, the behavior is undefined.

Как я понял, перед сдвигом имеет место приведение типа обоих операндов. Соответственно, результат (a<<8) уже не однобайтовый и дает 0xAA00. Если так, к какому типу приводится? От чего это зависит?


Корректен. UB здесь нет.

Почему результат (a<<8) не 0?

Потому, что все целочисленные операторы, размерностью меньше int приводятся к int перед операцией. Это называется integer promotion.

Если бы ты написал c = (a<<=8)|b, то получил бы c = b.

anonymous
()

Почему бы заранее не провести тип, раз есть сомнения? Кому-то же потом этот код поддерживать.

anonymous
()

Определение того, что такое «integer promotions», находится по индексу здесь:

6.3.1 Arithmetic operands
6.3.1.1 Boolean, characters, and integers
...
3 ... If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions. 48) All other types are unchanged by the integer promotions.

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от anonymous

разумно, но тут больше любопытство взыграло. хотелось разобраться. спасибо

tyro33
() автор топика
Ответ на: комментарий от xaizek

вот теперь все точно на своих местах, благодарю. надо было внимательнее читать стандарт

tyro33
() автор топика

IMHO в таких случаях имеет смысл использовать uint8_t, uint16_t и явное приведение перед сдвигом.

anonymous
()
Ответ на: комментарий от anonymous

UB тут все-таки слегка есть, ибо INT может быть разный (хотя маловероятно что он где-то окажется шириной в 1 октет).

RiseOfDeath ★★★★
()
Ответ на: комментарий от RiseOfDeath

Даже если бы int был в 8 бит, хоть он и не может быть меньше 16, собственно, как и short, то это всё равно не было бы UB. Так как 'a' объявлена как unsigned и её значение может превысить 127, то она кастанулась бы уже в unsigned int и операция сдвига проводилась бы в любом случае над положительным числом. Ну а если бы 'a' была signed с отрицательным значением, то размерность int'а тут бы никак не повлияла на наличие UB.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.