C - 按位操作

C - Bitwise manipulation

我是 C 的新手,我想了解 C 中的按位运算符 我在我面前找到了这段代码(将 2 转换为 37)

int main(void)
{
    int x = 2;
    x = (x<<x<<x) | (x<<x<<x) | (x << !!x) | !!x ;
    printf("%d\n" , x );  // prints 37 
}

这是我第一次看到这样的东西(x<<x<<x),我不明白它在做什么。 谁能详细解释一下代码中的第二行?

我建议你将这一长行分成几小段(有时尝试这样的事情会更有效;即仅阅读文档是不够的):

int x = 2;
printf("%d\n", x); // prints 2
printf("%d\n", x << x); // prints 8
printf("%d\n", x << x << x); // prints 32
printf("%d\n", !!x); // prints 1
printf("%d\n", x << !!x); // prints 4

printf("%d\n", x); // prints 2 (just to become sure that x was not changed)

因此,您知道初始长行等于 x = (32 | 32 | 1 | 4)。但是这是32+4+1=37.

详细看一下:

什么是<<>>

移位运算符将其左侧的值按位移动其右侧的位数:

  • <<左移右端补零
  • >> 如果值是无符号类型,则右移并添加 0,如果是有符号类型,则扩展最高位(以保留符号)。

C 标准还对 E1 >> E2 说:“如果 E1 具有带符号类型和负值,则结果值是实现定义的。”算术移位是不保证。

由于 << 是左结合的,因此 x<<x<<x 被计算为 (x<<x)<<x

另请参阅:什么是位移位 (bit-shift) 运算符,它们是如何工作的?

什么是!!x

它是一个一元 NOT 和一个一元 NOT。 !!x 可用作 shorthand 用于 (x != 0 ? 1 : 0)

这被称为 "obfuscation":编写不必要的复杂代码以使某些东西看起来更高级。

看子表达式x<<x<<x,就是简单的逻辑左移。移位运算符的运算符结合性是从左到右的,所以表达式等于(x<<x)<<x.

我们左移 2乘2得到8。8 << 2,左移8乘2得到32:

x = 32 | 32 | (x << !!x) | !!x ;

然后对于任何带有按位或 32 | 32 的表达式,其中操作数 32 相同,与只写 32 而不带或是完全一样的。所以相当于:

x = 32 | (x << !!x) | !!x ;

!! 是 C 中一个有点常见但晦涩的技巧,用于将任何整数转换为布尔值 0 或 1。!! 不是一个运算符,而是逻辑非运算符 [= 的两倍23=]。首先我们有 !20。然后 !0 得到 1。我们剩下这个:

x = 32 | (2 << 1) | 1;

2 << 1 是 4,所以:

x = 32 | 4 | 1;

写成二进制:

   0010 0000
OR 0000 0100
OR 0000 0001
------------
   0010 0101 = 0x25 hex = 37 dec