提取无符号 32 位整数的上下字

Extract upper and lower word of an unsigned 32-bit integer

要提取无符号 32 位整数的高位字和低位字并将每个字存储在单独的 uint16_t-variables 中,我按如下方式执行(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?如果有其他更有效的方法(如果有的话),您推荐哪些方法来代替这种方法来获得所需的结果?

不,您不需要类型转换,我建议您不要使用类型转换。这是因为它的优先级高于 & 运算符,所以 nbr 首先被转换为 uint16_t 然后被屏蔽。这也是为什么如果没有额外的括号,第二行将无法工作的原因。

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

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

口罩没用

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

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

例如 gcc -Wconversion 在没有强制转换的情况下产生警告

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

您在手术发生前施法。这意味着操作数 nbr 将通过强制转换显式转换,然后通过隐式整数提升立即隐式转换为 int。结果将是带符号的 int 类型。在这种情况下无害,但在其他情况下可能会造成麻烦。通过使用不正确的转换,您从 uint32_t 中创建了 signed int,这不是本意。

总体而言,您需要了解

不过,在分配回 uint16_t 时存在隐式左值转换,这在大多数情况下都可以节省时间。

还要注意 0x0000FFFF 是危险的风格。十六进制字面值是适合该值的类型,无论您在该值之前放置了多少个零。在这种情况下,它是 int 被签名的。在 16 位系统上,0x0000FFFF 会给出 int,而 0x00008000 会给出 unsigned int。 (例如检查这个奇怪的错误:

最佳实践、坚固、可移植、符合 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 个字节时

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

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%x\n Low : 0x%x\n Up  : 0x%x\n", my_var.word, my_var.reg.low, my_var.reg.up);

输出:

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