4

要提取无符号 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

4 回答 4

8

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

你在操作发生之前施放。这意味着操作数nbr将通过强制转换显式转换,然后int通过隐式整数提升立即隐式转换为。结果将是int已签名的类型。在这种情况下无害,但在其他情况下可能会造成麻烦。通过使用不正确的演员阵容,你做出了signed int一个uint32_t不是本意的事情。

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

虽然,在分配回 时存在隐式左值转换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强制转换之前。

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

于 2018-12-21T10:33:19.870 回答
6
uint16_t lower_word = (uint16_t) nbr;
uint16_t upper_word = (uint16_t) (nbr  >> 16);

口罩没用

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

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

例如gcc -Wconversion在没有演员表的情况下产生警告

于 2018-12-21T10:30:10.823 回答
2

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

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

于 2018-12-21T10:30:07.707 回答
-2

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

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
于 2018-12-21T10:39:53.350 回答