beyarkay Asked: 2024-12-12 16:00:10 +0800 CST2024-12-12 16:00:10 +0800 CST 2024-12-12 16:00:10 +0800 CST C 反转 16 位整数的位 772 此代码不会像预期的那样简单地反转 16 位整数的位: #include <stdint.h> typedef uint16_t U16; U16 myNum = 0xffff; ~myNum // 0xffff0000, not 0x0000 因为 C 在进行反转之前会将 16 位整数提升为 32 位整数(参见1、2 )。 对于 16 位按位反转,我有哪些选项?我能想到的有: ~myNum & 0xffff // or ((U16)~myNum) 但它们似乎容易出错/误解。如果我想要一个整洁的 16 位反转,我是不是运气不好? c 1 个回答 Voted Best Answer Lundin 2024-12-12T17:48:43+08:002024-12-12T17:48:43+08:00 简而言之:只需回到预期的类型,(uint16_t)~myNum 长话短说:问题确实是由于隐式提升,几乎所有以小整数类型(如char/short等)开始的 C 运算符最终都改为使用int类型。如果您uint16_t在 32 位机器上有一个并应用,这尤其麻烦~,因为操作数将提升为类型int,结果将为类型int,因此在这种情况下为负值。 的一般最佳实践~是始终将结果转换回预期类型,在本例中为(uint16_t)~myNum。转换为无符号是明确定义的,因为它取数学值模 2^n,其中 n 是无符号类型中的位数。或者,如果您愿意,只需丢弃 的高位字节int,剩下 0x0000。 此外,即使存在隐式提升,编译器也足够聪明,可以在(uint16_t)~myNum没有意外副作用(例如符号更改)的情况下判断出来。因此,如果这会导致更快的执行速度(在 8/16 位 CPU 上肯定是这种情况),它可以优化此表达式以在机器代码中执行 16 位类型。而像 这样的操作if(~myNum > 0)无法在 16 位上执行,因为隐式转换为 会int导致符号更改并给出负值。 最佳实践是永远不要编写包含或依赖隐式提升的代码,或者假装它不存在。例如myNum = ~myNum;也可以,但这段代码可能意味着两件事:要么程序员想到了隐式提升,但意识到在这种特定情况下它并不重要。或者程序员没有想到隐式提升,只是碰巧写对了代码。而最佳实践myNum = (uint16_t)~myNum;意味着程序员确实考虑过它,此外,这将消除编译器/静态分析器发出的有符号到无符号隐式转换警告。
简而言之:只需回到预期的类型,
(uint16_t)~myNum
长话短说:问题确实是由于隐式提升,几乎所有以小整数类型(如
char
/short
等)开始的 C 运算符最终都改为使用int
类型。如果您uint16_t
在 32 位机器上有一个并应用,这尤其麻烦~
,因为操作数将提升为类型int
,结果将为类型int
,因此在这种情况下为负值。的一般最佳实践
~
是始终将结果转换回预期类型,在本例中为(uint16_t)~myNum
。转换为无符号是明确定义的,因为它取数学值模 2^n,其中 n 是无符号类型中的位数。或者,如果您愿意,只需丢弃 的高位字节int
,剩下 0x0000。此外,即使存在隐式提升,编译器也足够聪明,可以在
(uint16_t)~myNum
没有意外副作用(例如符号更改)的情况下判断出来。因此,如果这会导致更快的执行速度(在 8/16 位 CPU 上肯定是这种情况),它可以优化此表达式以在机器代码中执行 16 位类型。而像 这样的操作if(~myNum > 0)
无法在 16 位上执行,因为隐式转换为 会int
导致符号更改并给出负值。最佳实践是永远不要编写包含或依赖隐式提升的代码,或者假装它不存在。例如
myNum = ~myNum;
也可以,但这段代码可能意味着两件事:要么程序员想到了隐式提升,但意识到在这种特定情况下它并不重要。或者程序员没有想到隐式提升,只是碰巧写对了代码。而最佳实践myNum = (uint16_t)~myNum;
意味着程序员确实考虑过它,此外,这将消除编译器/静态分析器发出的有符号到无符号隐式转换警告。