A. *_*nis 0 c bit-manipulation bit-shift bitwise-operators
我对C很新,我试图理解CI中的按位运算符在我面前找到这个代码(将2转换为37)
int main(void)
{
int x = 2;
x = (x<<x<<x) | (x<<x<<x) | (x << !!x) | !!x ;
printf("%d\n" , x ); // prints 37
}
Run Code Online (Sandbox Code Playgroud)
现在这是我第一次看到这样的东西 (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)
Run Code Online (Sandbox Code Playgroud)
所以,你知道初始长线等于x = (32 | 32 | 1 | 4).但这是32 + 4 + 1 = 37.
让我们详细看看:
什么是<<和>>?
移位运算符按位向右移位右边的位数:
<< 向左移动并在右端添加零.>> 向右移位并添加0,如果值是无符号类型,或者如果它是带符号类型则扩展顶部位(以保留符号).此外,C标准还说E1 >> E2:" 如果E1有一个带符号的类型和一个负值,则结果值是实现定义的. "算术移位不能保证.
由于<<是左关联的,因此x<<x<<x被评估为(x<<x)<<x.
什么是!!x?
这是一个一元的NOT和一个一元的NOT.
!!x可以用来作为速记(x != 0 ? 1 : 0).
这被称为“混淆”:编写不必要的复杂代码,以使某些东西看起来更高级。
查看子表达式x<<x<<x,它是简单的逻辑左移。移位运算符的运算符结合性是从左到右的,因此表达式等于(x<<x)<<x。
我们将 2 左移 2 次得到 8. 8 << 2,左移 8 次 2 得到 32:
x = 32 | 32 | (x << !!x) | !!x ;
Run Code Online (Sandbox Code Playgroud)
然后对于任何32 | 32操作数32相同的按位 OR 的表达式,与32不使用 OR 的写作完全相同。所以它等价于:
x = 32 | (x << !!x) | !!x ;
Run Code Online (Sandbox Code Playgroud)
!!是在 C 中将任何整数转换为布尔值 0 或 1 的一个有点常见但晦涩的技巧。!!不是一个运算符,而是逻辑 not 运算符的两倍!。首先我们有!2哪个是0。那么!0这给1. 我们只剩下这个:
x = 32 | (2 << 1) | 1;
Run Code Online (Sandbox Code Playgroud)
2 << 1 是 4,所以:
x = 32 | 4 | 1;
Run Code Online (Sandbox Code Playgroud)
写成二进制:
0010 0000
OR 0000 0100
OR 0000 0001
------------
0010 0101 = 0x25 hex = 37 dec
Run Code Online (Sandbox Code Playgroud)