提取无符号32位整数的高位和低位字

时间:2018-12-21 10:18:18

标签: c word uint32 uint16

要提取一个无符号的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?您是否建议使用其他更有效的方法(如果有)代替这种方法来获得所需的结果?

4 个答案:

答案 0 :(得分:7)

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

面具没用

必须进行广播,否则编译器可能会产生警告

{编辑以考虑到伦丁/埃里克·波斯特皮希尔(Eric Postpischil)的话}

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

答案 1 :(得分:7)

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

您在进行该操作之前进行了投射。这意味着操作数nbr将通过强制转换进行显式转换,然后立即通过隐式整数提升将其隐式转换为int。结果将为int类型,并已签名。在这种情况下无害,但在其他情况下可能引起麻烦。通过使用不正确的转换,您在signed int中做出了uint32_t,这不是故意的。

总体而言,您需要注意Implicit type promotion rules

尽管,在分配回uint16_t时会有一个隐式的左值转换,这在大多数情况下可以节省时间。

还要注意,0x0000FFFF是危险的样式。十六进制文字是值适合的类型,而不管您在值之前放置多少个零。在这种情况下,int已签名。在16位系统上,0x0000FFFF将给出int,而0x00008000将给出unsigned int。 (例如,检查以下奇怪的错误:Why is 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个字节时。

答案 2 :(得分:1)

不,您不需要打字机,我建议不要使用。这是因为它比&运算符具有更高的优先级,因此nbr首先被转换为uint16_t,然后被屏蔽。这也是为什么第二行如果没有附加括号就无法工作的原因。

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

答案 3 :(得分:-3)

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

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