Преобразование 32-разрядного целочисленного значения в 16-разрядное целое число без знака - PullRequest
0 голосов
/ 03 января 2019

О чем говорит стандарт C:

uint32_t a = 0x11223344;
uint16_t b = a;

При печати я получаю 0x3344, что имеет смысл;так что это должно быть законным и правильным поведением?

1 Ответ

0 голосов
/ 03 января 2019

То, что говорит стандарт C, сводится к тому, что 0x11223344 преобразуется в uint16_t путем вычисления значения по модулю 2 16 , которое составляет 0x3344.

Однако процесс, с помощью которого он туда попадает, имеет несколько этапов:

uint16_t b = a; - это объявление с инициализацией, которое обсуждается в C 2018 6.7.9 11:

Инициализатор для скаляра должен быть одним выражением, необязательно заключенным в фигурные скобки. Начальное значение объекта - это значение выражения (после преобразования); применяются те же ограничения и преобразования типов, что и для простого присваивания, принимая тип скаляра за неквалифицированную версию объявленного им типа.

Таким образом, применяются правила простого назначения. Они обсуждаются в 6.5.16.1 2:

В простом назначении ( = ) значение правого операнда преобразуется в тип выражения присваивания и заменяет значение, сохраненное в объекте, обозначенном левым операндом .

«Тип выражения присваивания» - это тип левого операнда, согласно 6.5.16 3:

Типом выражения присваивания является тип, который левый операнд будет иметь после преобразования lvalue.

(В этом случае нет ничего примечательного в преобразовании lvalue; объект uint16_t b просто станет значением uint16_t, поэтому тип будет uint16_t.)

Тип uint16_t, конечно, 16-разрядное целое число без знака, согласно 7.20.1.1 1:

Имя typedef uint N _t обозначает целочисленный тип без знака с шириной N и без битов заполнения.

Обратите внимание, что в качестве 16-разрядного целого числа без знака его максимальное значение равно 65535, а еще одно - 65536 (2 16 ). Это актуально для последнего шага, преобразования из правого операнда в uint16_t, который обсуждается в 6.3.1.3 1 и 2:

Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool , если значение может быть представлено новым типом, оно не изменяется.

В противном случае, если новый тип является беззнаковым, значение преобразуется путем многократного добавления или вычитания значения, превышающего максимальное значение, которое может быть представлено в новом типе, до тех пор, пока значение не окажется в диапазоне нового типа.

Когда мы вычитаем 65536 (0x10000) из 0x11223344 0x1122 раз, результат равен 0x3344, который может быть представлен uint16_t, так что это результат преобразования.

...