То, что говорит стандарт 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
, так что это результат преобразования.