c - Bit Twiddling - 对该程序的输出感到困惑

标签 c integer bit-shift bit-manipulation

所以我在 C 中摆弄 Bit-Twiddling,我遇到了一个有趣的输出:

int main()
{
    int a = 0x00FF00FF;
    int b = 0xFFFF0000;

    int res = (~b & a);

    printf("%.8X\n", (res << 8) | (b >> 24));
}

这条语句的输出是:

FFFFFFFF

我希望输出是

0000FFFF

但为什么不是呢?我是否遗漏了这里的位移位?

最佳答案

TLDR:您的整数 b 是负数,因此当您将其右移时,最高位(即 1)的值保持不变。因此,当您将 b 右移 24 位时,您最终会得到 0xFFFFFFFF。

更长的解释:

假设在您的平台上您的整数是 32 位或更长,并且有符号整数由 2 的补码表示,那么分配给有符号整数变量的 0xFFFF0000 是一个负数。如果 int 长度超过 32 位,则 0xFFFF0000 将首先进行符号扩展,并且仍然是负数。

将负数右移是标准定义的实现(C99/N1256,第 6.5.7.5 节):

The result of E1 >> E2 is E1 right-shifted E2 bit positions. [...] If E1 has a signed type and a negative value, the resulting value is implementation defined.

这意味着特定的编译器可以选择在特定情况下发生什么,但应该在编译器手册中注明效果是什么。

在许多处理器中往往有两组移位指令,逻辑移位和算术移位。逻辑右移将移位位并用零填充暴露的位。算术右移(再次假设 2 的补码)将用最高有效位的相同位值填充暴露的位,以便最终得到与使用移位作为除以 2 一致的结果。(例如,-4 >> 1 == 0xFFFFFFFC >> 1 == 0xFFFFFFFE == -2.)

在您的情况下,编译器实现者似乎选择在应用于有符号整数时使用算术移位,因此将负值向右移动的结果仍然是负值。就位模式而言​​ 0xFFFF0000 >> 24 给出 0xFFFFFFFF。

除非您完全确定自己在做什么,否则最好只对无符号类型执行按位运算,因为它们的内部表示可以安全地被视为位的集合。您可能还想通过将无符号后缀附加到您的数字来确保您在这种情况下使用的任何数值都是无符号的。

关于c - Bit Twiddling - 对该程序的输出感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9928251/

相关文章:

c - 如何使用CMOCKA框架运行c单元测试用例?

java - JOptionPane 输入到 int

c++ - 将 CryptoPP::Integer 转换为 LPCTSTR

Java "Bit Shifting"教程?

c++ - C++ 中从 24 位到 32 位的签名扩展

c++ - 将移位运算符应用于已定义的有符号类型 : UB and Impl.

c++ - 计算 fib(n) 被调用 FOR EACH n 的次数

c - 有没有办法在返回数组时不使用指针? (警告: passing argument 1 of 'arrangef' makes pointer from integer without a cast.)

c - 带有 "if"的循环无法正常工作

c++ - 在这种情况下,我将如何循环遍历所有各种可能性?