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=]。首先我们有 !2
即 0
。然后 !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
我是 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=]。首先我们有 !2
即 0
。然后 !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