Система типа С является одновременно тонкой и опасной.Явное преобразование может или не может быть необходимым.В частности, (uint16_t) nbr & 0x0000FFFF
приведение не является правильным, предполагая 32-битный процессор.
Вы разыгрываете до того, как произойдет операция.Это означает, что операнд nbr
будет явно преобразован приведением, а затем немедленно неявно преобразован до int
путем неявного целочисленного продвижения.Результат будет иметь тип int
, который подписан.Безвреден в этом случае, но может вызвать проблемы в других случаях.Используя неправильный состав, вы сделали signed int
из uint32_t
, который не был намерением.
В целом вам необходимо знать о неявных правилах продвижения типа .
Несмотря на то, что при присваивании происходит неявное преобразование lvalue обратно в uint16_t
, что большую часть времени экономит день.
Также обратите внимание, что 0x0000FFFF
- это опасный стиль.Шестнадцатеричные литералы относятся к тому типу, где значение будет соответствовать, независимо от того, сколько нулей вы ставите перед значением.В этом случае это int
, который подписан.В 16-битной системе 0x0000FFFF
даст int
, но 0x00008000
даст unsigned int
.(Проверьте эту странную ошибку, например: Почему 0 <-0x80000000? </a>)
Лучшая практика, надежный, переносимый, совместимый с MISRA-C код, - это код, который не содержит никаких неявныхконверсии вообще:
uint32_t nbr = ...;
uint16_t lower_word = (uint16_t) (nbr & 0xFFFFUL);
uint16_t upper_word = (uint16_t) ((nbr >> 16) & 0xFFFFUL);
Предполагается, что nbr
известно как uint32_t
, в противном случае рекомендуется приводить этот операнд к uint32_t
перед приведением.
Маскина самом деле не нужны в этом конкретном случае, но в общем случае, например, когда маскируются 4 байта из uint32_t
.