简体   繁体   English

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

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

To extract the upper and lower word of an unsigned 32-bit integer and store each one in separate uint16_t-variables I do as follows ( nbr is an unsigned 32-bit integer): 要提取无符号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

Is the explicit conversion to an uint16_t unnecessary? 显式转换为uint16_t是不必要的吗? What other more effective ways, if there are any, do you recommend to obtain the desired results instead of this approach? 还有什么其他更有效的方法,如果有的话,你建议获得所需的结果而不是这种方法吗?

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

masks are useless 面具没用

cast are necessary else the compiler could produce warning cast是必要的,否则编译器可能会产生警告

{edit to take into account the remark of Lundin / Eric Postpischil} {编辑以考虑Lundin / Eric Postpischil的评论}

for instance gcc -Wconversion produces a warning without the cast 例如, gcc -Wconversion会在没有gcc -Wconversion生成警告

The C type system is both subtle and dangerous. C型系统既微妙又危险。 The explicit conversion may or may not be necessary. 显式转换可能是必要的,也可能不是必需的。 In case of (uint16_t) nbr & 0x0000FFFF specifically, the cast is not correct, assuming 32 bit CPU. (uint16_t) nbr & 0x0000FFFF情况下,假设32位CPU,转换是不正确的。

You cast before the operation takes place. 你在行动发生前施放。 Meaning that the operand nbr will get explicitly converted by the cast, and then immediately implicitly converted up to int by implicit integer promotion. 意味着操作数nbr将由nbr转换显式转换,然后通过隐式整数提升立即隐式转换为int The result will be of type int , which is signed. 结果将是int类型,已签名。 Harmless in this case but can cause trouble in other cases. 在这种情况下无害但在其他情况下会引起麻烦。 By using the incorrect cast you made a signed int out of a uint32_t which was not the intention. 通过使用不正确的uint32_t ,您从uint32_t创建了一个signed int ,这不是意图。

Overall you need to be aware of Implicit type promotion rules . 总的来说,您需要了解隐式类型促销规则

Although, there is an implicit lvalue conversion upon assignment back to uint16_t , which most of the time saves the day. 虽然,在分配回uint16_t时会有一个隐含的左值转换,大部分时间都会节省一天。

Also note that 0x0000FFFF is dangerous style. 另请注意, 0x0000FFFF是危险的风格。 Hex literals are of the type where the value will fit, regardless of how many zeroes you put before the value. 无论您在值之前放置多少个零,Hex文字都是值适合的类型。 In this case, it is int which is signed. 在这种情况下,它是签名的int On a 16 bit system, 0x0000FFFF would give int but 0x00008000 would give unsigned int . 在16位系统上, 0x0000FFFF将给出int0x00008000将给出unsigned int (Check this weird bug for example: Why is 0 < -0x80000000? ) (例如,检查这个奇怪的bug: 为什么0 <-0x80000000?

The best practice, rugged, portable, MISRA-C compliant code, is code which does not contain any implicit conversions at all: 最佳实践,坚固耐用,可移植,符合MISRA-C的代码,是完全不包含任何隐式转换的代码:

uint32_t nbr = ...;
uint16_t lower_word = (uint16_t) (nbr & 0xFFFFUL);
uint16_t upper_word = (uint16_t) ((nbr >> 16) & 0xFFFFUL);

This assuming nbr is known to be uint32_t , otherwise it is best practice to cast that operand to uint32_t before casts. 假设nbr已知为uint32_t ,否则最好在强制转换之前将该操作数强制转换为uint32_t

The masks are not really necessary in this specific case, but in the general case, for example when masking out 4 bytes from a uint32_t . 在这种特定情况下,掩码并不是必需的,但在一般情况下,例如从uint32_t屏蔽掉4个字节时。

No, you don't need the typecast and i would recommend not to use one. 不,你不需要类型转换,我建议不要使用一个。 This is because it has a higher precedence than the & operator, so nbr is first converted to uint16_t and then masked. 这是因为它具有比&运算符更高的优先级,因此nbr首先转换为uint16_t然后被屏蔽。 This is also why the second line would not work without the additional parentheses. 这也是为什么第二行在没有附加括号的情况下不起作用的原因。

Apart from that the code is just fine, and there is no real reason to use a different approach. 除此之外,代码很好,并没有真正的理由使用不同的方法。 You could also do the shift first and then mask the value, but the resulting assembler code should be exactly the same. 您也可以先执行shift,然后屏蔽该值,但生成的汇编代码应该完全相同。

If you need to repeat this operation multiple times in your code, there is another way of doing so using unions : 如果您需要在代码中多次重复此操作,还有另一种方法可以使用联合:

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

Declare your variable as follows : 声明您的变量如下:

uplow my_var;
my_var.word = nbr;

Use it like that : 像这样使用它:

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

Output : 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM