C 反转 16 位整数的位

问题描述 投票:0回答:1

此代码不会简单地按预期反转 16 位整数的位:

#include <stdint.h>
typedef uint16_t U16;

U16 myNum = 0xffff;
~myNum // 0xffff0000, not 0x0000

因为 C 在进行反转之前会将 16 位整数提升为 32 位整数(参见 12)。

16 位按位反转有哪些选项?我能想到:

~myNum & 0xffff
// or 
((U16)~myNum)

但他们似乎容易出错/误解。如果我想要一个简洁的 16 位反转,我是不是运气不好?

c bitwise-operators
1个回答
0
投票

短篇故事:直接投射回想要的类型,

(uint16_t)~myNum


长话短说:问题确实是,由于隐式提升,几乎所有以小整数类型开始的 C 运算符(例如

char
/
short
等)最终都使用
int
类型。如果您在 32 位机器上有
uint16_t
并应用
~
,这会特别麻烦,因为操作数将提升为
int
类型,结果将是
int
类型,因此在这个案例。

使用

~
的一般最佳实践是始终将结果转换回预期类型,在本例中为
(uint16_t)~myNum
。到无符号的转换是根据数学值模 2^n 明确定义的,其中 n 是无符号类型的位数。或者,如果您愿意,只需丢弃
int
的高位字节,留下 0x0000。

此外,即使存在隐式提升,编译器也足够聪明,可以告诉您,在

(uint16_t)~myNum
的情况下,不会出现意外的副作用,例如符号更改。因此,它可以优化此表达式以在机器代码中执行 16 位类型,如果这会导致更快的执行速度(当然是 8/16 位 CPU 上的情况)。而像
if(~myNum > 0)
这样的东西无法在 16 位上执行,因为到
int
的隐式转换导致符号性发生变化并给出负值。

最佳实践是永远不要编写包含或依赖隐式提升的代码,或者假装它不存在。例如

myNum = ~myNum;
也可以工作,但这段代码可能意味着两件事:要么程序员想到了隐式提升,但意识到在这种特定情况下这并不重要。或者程序员没有想到隐式提升,只是运气好才得到了正确的代码。而最佳实践
myNum = (uint16_t)~myNum;
意味着程序员确实考虑过它,此外,这还将消除来自编译器/静态分析器的有符号到无符号隐式转换警告。

© www.soinside.com 2019 - 2024. All rights reserved.