提取无符号 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
要提取无符号 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
.
如果您需要在代码中多次重复此操作,还有另一种使用联合的方法:
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