c语言 - 提取无符号 32 位整数的上字和小字



要提取无符号 32 位整数的上字和下字并将每个字存储在单独的uint16_t变量中,我按如下方式操作(nbr是一个无符号的 32 位整数):

uint16_t lower_word = (uint16_t) nbr & 0x0000FFFF;  // mask desired word
uint16_t upper_word = (uint16_t) ((nbr & 0xFFFF0000) >> 16); // right-shift after masking

是否没有必要显式转换为uint16_t?您建议还有哪些其他更有效的方法(如果有)来获得所需的结果而不是这种方法?

C型系统既微妙又危险。显式转换可能是必需的,也可能不是必需的。在具体(uint16_t) nbr & 0x0000FFFF的情况下,假设 CPU 为 32 位,则强制转换不正确。

在操作发生之前进行投射。这意味着操作数nbr将由强制转换显式转换,然后立即通过隐式整数提升隐式转换为int。结果将是int类型,它是有符号的。在这种情况下无害,但在其他情况下可能会造成麻烦。通过使用不正确的投射,您从并非意图的uint32_t中进行了signed int

总的来说,您需要了解隐式类型升级规则。

虽然,在赋值回uint16_t时有一个隐式的左值转换,这在大多数情况下可以节省一天的时间。

另请注意,0x0000FFFF是危险的风格。十六进制文本属于适合值的类型,无论您在值前放置多少个零。在这种情况下,签名的是int。在 16 位系统上,0x0000FFFF会给出int0x00008000会给出unsigned int。(例如,检查这个奇怪的错误:为什么 0 <-0x80000000?

最佳实践,坚固,可移植,符合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

在这种特定情况下,掩码并不是真正必要的,但在一般情况下,例如从uint32_t屏蔽 4 个字节时。

uint16_t lower_word = (uint16_t) nbr;
uint16_t upper_word = (uint16_t) (nbr  >> 16);

口罩没用

强制转换是必需的,否则编译器可能会产生警告

{编辑以考虑到Lundin/Eric Postpischil的评论}

例如,gcc -Wconversion产生没有强制转换的警告

不,你不需要类型转换,我建议不要使用。这是因为它比 & 运算符具有更高的优先级,因此 nbr 首先转换为 uint16_t,然后被屏蔽。这也是为什么没有额外的括号,第二行就不起作用的原因。

除此之外,代码很好,没有真正的理由使用不同的方法。您也可以先进行移位,然后屏蔽该值,但生成的汇编程序代码应完全相同。

如果您需要在代码中多次重复此操作,还有另一种使用联合的方法

typedef union _uplow                                                                                     
{                                                                                                        
struct _reg {                                                                                          
uint32_t low : 16;                                                                                   
uint32_t up  : 16;                                                                                   
} reg;                                                                                                 
uint32_t word;                                                                                         
} uplow;

按如下方式声明变量:

uplow my_var;
my_var.word = nbr;

像这样使用它:

printf ("Word : 0x%xn Low : 0x%xn Up  : 0x%xn", my_var.word, my_var.reg.low, my_var.reg.up);

输出:

Word : 0xaaaabbbb
Low : 0xbbbb
Up  : 0xaaaa

最新更新