本文翻译自:What is the >>>= operator in C?
Given by a colleague as a puzzle, I cannot figure out how this C program actually compiles and runs. 由同事作为一个谜题,我无法弄清楚这个C程序实际上是如何编译和运行的。 What is this >>>=
operator and the strange 1P1
literal? 这是什么>>>=
运算符和奇怪的1P1
字面值? I have tested in Clang and GCC. 我在Clang和GCC进行了测试。 There are no warnings and the output is "???" 没有警告,输出是“???”
#include <stdio.h>
int main()
{
int a[2]={ 10, 1 };
while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
printf("?");
return 0;
}
#1楼
参考:https://stackoom.com/question/1IYqm/什么是C中的-运算符
#2楼
It is some rather obscure code involving digraphs , namely <:
and :>
which are alternative tokens for [
and ]
respectively. 这是一些涉及有向图的相当模糊的代码,即<:
和:>
分别是[
和]
替代。 There is also some use of the conditional operator . 还有一些使用条件运算符 。 There is also a bit shifting operator , the right shift assignment >>=
. 还有一个位移位运算符 ,右移位赋值>>=
。
This is a more readable version: 这是一个更易读的版本:
while( a[ 0xFULL ? '\0' : -1 ] >>= a[ !!0X.1P1 ] )
and an even more readable version, replacing the expressions in the []
for the values they resolve to: 以及更可读的版本,将[]
的表达式替换为它们解析的值:
while( a[0] >>= a[1] )
Replacing a[0]
and a[1]
for their values should make it easy to figure out what the loop is doing, ie the equivalent of: 更换a[0]
和a[1]
的值应该可以很容易地找出循环正在做什么,即相当于:
int i = 10;
while( i >>= 1)
which is simply performing (integer) division by 2 in each iteration, producing the sequence 5, 2, 1
. 这是在每次迭代中简单地执行(整数)除以2,产生序列5, 2, 1
。
#3楼
The line: 这条线:
while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
contains the digraphs :>
and <:
, which translate to ]
and [
respectively, so it's equivalent to: 包含有向图 :>
和<:
:,它们分别转换为]
和[
因此它相当于:
while( a[ 0xFULL?'\0':-1 ] >>= a[ !!0X.1P1 ] )
The literal 0xFULL
is the same as 0xF
(which is hex for 15
); 文字0xFULL
与0xF
( 15
为十六进制)相同; the ULL
just specifies that it's an unsigned long long
literal . ULL
只是指定它是一个unsigned long long
文字 。 In any case, as a boolean it's true, so 0xFULL ? '\\0' : -1
在任何情况下,作为布尔值它是真的,所以0xFULL ? '\\0' : -1
0xFULL ? '\\0' : -1
evaluates to '\\0'
, which is a character literal whose numerical value is simply 0
. 0xFULL ? '\\0' : -1
计算结果为'\\0'
,这是一个字符文字,其数值只是0
。
Meanwhile, 0X.1P1
is a hexadecimal floating point literal equal to 2/16 = 0.125. 同时, 0X.1P1
是十六进制浮点文字,等于2/16 = 0.125。 In any case, being non-zero, it's also true as a boolean, so negating it twice with !!
在任何情况下,非零,它也是一个布尔值,所以否定它两次!!
again produces 1
. 再次产生1
。 Thus, the whole thing simplifies down to: 因此,整个过程简化为:
while( a[0] >>= a[1] )
The operator >>=
is a compound assignment that bit-shifts its left operand right by the number of bits given by the right operand, and returns the result. 运算符>>=
是一个复合赋值 ,它将左操作数右移一位右操作数给出的位数,并返回结果。 In this case, the right operand a[1]
always has the value 1
, so it's equivalent to: 在这种情况下,右操作数a[1]
的值始终为1
,因此它等效于:
while( a[0] >>= 1 )
or, equivalently: 或者,等效地:
while( a[0] /= 2 )
The initial value of a[0]
is 10. After shifting right once, it become 5, then (rounding down) 2, then 1 and finally 0, at which point the loop ends. a[0]
的初始值为10.右移一次后,变为5,然后(向下舍入)2,然后是1,最后是0,此时循环结束。 Thus, the loop body gets executed three times. 因此,循环体被执行三次。
#4楼
Let's go through the expression left-to-right: 让我们从左到右表达:
a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ]
The first thing I notice is that we are using the ternary operator from the use of ?
我注意到的第一件事是我们使用的是三元运算符?
. 。 So the subexpression: 所以子表达式:
0xFULL ? '\0' : -1
is saying "if 0xFULL
is non-zero, return '\\0'
, otherwise -1
. 0xFULL
is a hexadecimal literal with the unsigned long-long suffix - meaning it's a hexadecimal literal of type unsigned long long
. That doesn't really matter though, because 0xF
can fit inside a regular integer. 是在说:“如果0xFULL
是非零,返回'\\0'
,否则-1
。 0xFULL
是一个十六进制文字与无符号长隆后缀 -这意味着它的文本类型的十六进制unsigned long long
,这其实并不重要但是,因为0xF
可以适合常规整数。
Also, the ternary operator converts the types of the second and third terms to their common type. 此外,三元运算符将第二项和第三项的类型转换为它们的公共类型。 '\\0'
is then converted to int
, which is just 0
. 然后将'\\0'
转换为int
,它只是0
。
The value of 0xF
is way bigger than zero, so it passes. 0xF
的值大于零,因此它通过。 The expression now becomes: 表达式现在变为:
a[ 0 :>>>=a<:!!0X.1P1 ]
Next, :>
is a digraph . 接下来, :>
是有向图 。 It is a construct that expands to ]
: 它是一个扩展为]
:
a[0 ]>>=a<:!!0X.1P1 ]
>>=
is the signed right shift operator, we can space that out from a
to make it clearer. >>=
是签名的右移操作符,我们可以将其从a
中移出以使其更清晰。
Moreover, <:
is a digraph that expands to [
: 而且, <:
是一个扩展为[
:的有向图
a[0] >>= a[!!0X.1P1 ]
0X.1P1
is a hexadecimal literal with an exponent. 0X.1P1
是带有指数的十六进制文字。 But no matter the value, the !!
但无论价值如何, !!
of anything that's non-zero is true. 任何非零的都是真的。 0X.1P1
is 0.125
which is non-zero, so it becomes: 0X.1P1
是0.125
非零,因此变为:
a[0] >>= a[true]
-> a[0] >>= a[1]
The >>=
is the signed right shift operator. >>=
是签名的右移运算符。 It changes the value of its left operand by shifting its bits forward by the value on the operator's right side. 它通过将其位向前移动操作员右侧的值来改变其左操作数的值。 10
in binary is 1010
. 二进制10
是1010
。 So here are the steps: 所以这里是步骤:
01010 >> 1 == 00101
00101 >> 1 == 00010
00010 >> 1 == 00001
00001 >> 1 == 00000
>>=
returns the result of its operation, so as long as shifting a[0]
remains non-zero for every time its bits are shifted right by one, the loop will continue. >>=
返回其操作的结果,因此只要移位a[0]
每次将其位右移1时都保持非零,循环将继续。 The fourth attempt is where a[0]
becomes 0
, so the loop is never entered. 第四次尝试是a[0]
变为0
,因此永远不会输入循环。
As a result, ?
结果, ?
is printed three times. 打印三次。