C中的>>> =运算符是什么?

由同事给出的一个难题,我不知道这个C程序是如何编译和运行的。 这是什么>>>=运算符和奇怪的1P1文字? 我已经在Clang和GCCtesting过了。 没有警告,输出是“???”

 #include <stdio.h> int main() { int a[2]={ 10, 1 }; while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] ) printf("?"); return 0; } 

该行:

 while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] ) 

包含有向图 :><: :,分别翻译为][ ,所以它相当于:

 while( a[ 0xFULL?'\0':-1 ] >>= a[ !!0X.1P1 ] ) 

文字0xFULL0xF (hex为15 )相同; ULL只是指定它是一个unsigned long long文字 。 在任何情况下,作为一个布尔值是真的,所以0xFULL ? '\0' : -1 0xFULL ? '\0' : -1计算结果为'\0' ,它是一个数字值仅为0的字符 。

同时, 0X.1P1是一个等于2/16 = 0.125的hex浮点数字 。 在任何情况下,非零,它也是一个布尔值,所以用两个否定它!! 再次产生1 。 因此,整个事情简化到:

 while( a[0] >>= a[1] ) 

运算符>>=是一个复合赋值 ,它将左操作数右移位右操作数给出的位数,并返回结果。 在这种情况下,右操作数a[1]的值总是1 ,所以它相当于:

 while( a[0] >>= 1 ) 

或者等价地:

 while( a[0] /= 2 ) 

a[0]的初始值为10.右移一次后,变为5,然后(舍入)2,然后是1,最后是0,此时循环结束。 因此,循环体被执行三次。

这是一些相当模糊的代码,涉及有向图 ,即<::> ,它们分别是[]替代记号。 还有一些使用条件运算符 。 还有一个移位操作符 ,右移位赋值>>=

这是一个更可读的版本:

 while( a[ 0xFULL ? '\0' : -1 ] >>= a[ !!0X.1P1 ] ) 

和一个更具可读性的版本,将它们所parsing的值replace为[]的expression式:

 while( a[0] >>= a[1] ) 

用它们的值代替a[0]a[1]可以很容易地找出循环的作用,即相当于:

 int i = 10; while( i >>= 1) 

它在每次迭代中简单地执行(整数)除2,产生序列5, 2, 1

让我们通过从左到右的expression式:

 a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] 

我注意到的第一件事就是我们使用三元运算符来使用? 。 所以这个子expression式:

 0xFULL ? '\0' : -1 

如果0xFULL不为零,则返回'\0' ,否则返回-1 0xFULL是一个hex字面值,带有无符号的long-long后缀 – 意味着它是一个unsigned long longtypes的hex文字,这并不重要虽然,因为0xF可以适应一个正则整数。

此外,三元运算符将第二和第三项的types转换为它们的通用types。 然后'\0'被转换为int ,这只是0

0xF的值比零大,所以通过。 expression现在变成:

 a[ 0 :>>>=a<:!!0X.1P1 ] 

接下来, :>是一个有向图 。 这是一个扩展到]的构造:

 a[0 ]>>=a<:!!0X.1P1 ] 

>>=是有符号的右移运算符,我们可以将其从a中排除,以使其更清楚。

而且, <:是一个扩展为[

 a[0] >>= a[!!0X.1P1 ] 

0X.1P1是一个带指数的hex文字。 但不pipe价值!! 任何非零的东西都是真的。 0X.1P10.125 ,它是非零的,所以它变成:

 a[0] >>= a[true] -> a[0] >>= a[1] 

>>=是有符号的右移运算符。 它通过向右移动操作符右侧的值来改变左操作数的值。 十进制是1010 。 所以这里是步骤:

 01010 >> 1 == 00101 00101 >> 1 == 00010 00010 >> 1 == 00001 00001 >> 1 == 00000 

>>=返回操作的结果,所以只要每次移位a[0]保持非零,则循环将继续。 第四次尝试是a[0]变为0 ,所以循环从不input。

结果, ? 打印三次。