292 votes

Qu'est-ce que le >>>= opérateur en C?

Donné par un collègue comme un puzzle, je ne peux pas comprendre comment cela C programme compile et s'exécute. Qu'est-ce que ce >>>= opérateur et de l'étrange 1P1 littérale? Je l'ai testé dans clang et de la GCC. Il n'y a pas d'avertissements et la sortie est "???"

#include <stdio.h>

int main()
{
    int a[2]={ 10, 1 };

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

    return 0;
}

466voto

Ilmari Karonen Points 20585

La ligne:

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

contient les bigrammes :> et <:, qui se traduisent ] et [ respectivement, alors qu'elle est équivalente à:

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

Le littéral 0xFULL est le même que 0xF (ce qui est hex pour 15); l' ULL seulement précise que c'est un unsigned long long littérale. En tout cas, comme un booléen, c'est vrai, alors 0xFULL ? '\0' : -1 évalue '\0', ce qui est un littéral de caractère dont la valeur numérique est tout simplement 0.

En attendant, 0X.1P1 est une hexadécimal à virgule flottante littérale égal à 2/16 = 0.125. Dans tous les cas, étant non nul, il est vrai aussi comme un booléen, donc niant deux fois avec !! nouveau produit 1. Ainsi, tout ça simplifie:

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

L'opérateur >>= est un composé d'affectation qui peu-quarts de son opérande de gauche à droite par le nombre de bits donné par l'opérande de droite, et retourne le résultat. Dans ce cas, l'opérande de droite a[1] a toujours la valeur 1, il est donc équivalente à:

while( a[0] >>= 1 )

ou, de manière équivalente:

while( a[0] /= 2 )

La valeur initiale de l' a[0] est de 10. Après le passage de droite une fois, il devient de 5, puis (arrondi vers le bas) 2, puis 1 et enfin 0, la boucle se termine. Ainsi, le corps de la boucle est exécuté trois fois.

67voto

juanchopanza Points 115680

Il est assez obscur code impliquant des bigrammes, à savoir l' <: et :> qui sont d'autres jetons pour [ et ] respectivement. Il y a aussi une certaine utilisation de l' opérateur conditionnel. Il y a aussi un décalage de bits de l'opérateur, le décalage à droite de cession >>=.

C'est une version plus lisible:

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

et une version plus lisible, en remplaçant les expressions de la [] pour les valeurs qu'ils ont à résoudre:

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

Remplacement d' a[0] et a[1] de leurs valeurs doit rendre plus faciles à comprendre ce que la boucle est en train de faire, c'est à dire l'équivalent de:

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

qui est tout simplement effectuer (entier) de la division par 2 à chaque itération, la production de la séquence de 5, 2, 1.

41voto

0x499602D2 Points 36421

Reprenons l'expression de gauche à droite:

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

La première chose que je remarque, c'est que nous sommes à l'aide de l'opérateur ternaire de l'utilisation de ?. Si la sous-expression:

0xFULL ? '\0' : -1

est-disant "si 0xFULL est non-nul, le retour '\0', sinon, -1. 0xFULL est une hexadécimal littérale avec le unsigned long long suffixe - sens, c'est une hexadécimal littéral de type unsigned long long. Qui n'a pas vraiment d'importance, parce qu' 0xF peut s'adapter à l'intérieur d'un régulier entier.

Aussi, l'opérateur ternaire convertit les types de la deuxième et troisième termes de leur type. '\0' est ensuite convertie en int, ce qui est juste 0.

La valeur de 0xF est plus grand que zéro, de sorte qu'il passe. L'expression devient alors:

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

Ensuite, :> est un digraphe. C'est une construction qui permet de ]:

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

>>= est la signature de l'opérateur de décalage à droite, nous pouvons espace de a pour la rendre plus claire.

De plus, en <: est un digraphe qui s'étend à l' [:

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

0X.1P1 est une hexadécimal littérale avec un exposant. Mais peu importe la valeur, l' !! de tout ce qui est non-nulle est vraie. 0X.1P1 est 0.125 qui est non-nul, de sorte qu'il devient:

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

L' >>= est la signature de l'opérateur de décalage à droite. Il modifie la valeur de son opérande de gauche en déplaçant ses bits de l'avant par la valeur de l'exploitant du côté droit. 10 en binaire est - 1010. Donc, voici les étapes:

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

>>= retourne le résultat de son opération, tant et aussi longtemps que de changer de a[0] reste non nul de tous les temps ses bits sont décalés à droite par un, la boucle continue. La quatrième tentative est où a[0] devient 0, de sorte que la boucle n'est jamais entré.

En conséquence, ? est imprimé trois fois.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X