Co to jest operator > = w C?

Podane przez kolegę jako zagadka, nie mogę zrozumieć, jak ten program C faktycznie kompiluje i działa. Co to jest operator >>>= i dziwny 1P1 dosłowny? Testowałem w Clang i GCC. Nie ma żadnych ostrzeżeń, a wyjście to"???"

#include <stdio.h>

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

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

    return 0;
}
Author: TLama, 2014-08-26

3 answers

Linia:

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

Zawiera digrafy :> i <:, które tłumaczą się odpowiednio na ] i [, więc jest równoważne:

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

Literał 0xFULL jest taki sam jak 0xF (co jest szesnastkowe dla 15); ULLokreśla tylko, że jest tounsigned long long literał . W każdym razie, jako boolean jest to prawda, więc 0xFULL ? '\0' : -1 ewaluuje do '\0', który jest literałem znaków, którego wartość liczbowa jest po prostu 0.

Tymczasem 0X.1P1 jest a szesnastkowy literał zmiennoprzecinkowy równy 2/16 = 0,125. W każdym razie, jako niezerowe, jest również prawdziwe jako boolean, więc negowanie go dwa razy z !! ponownie daje 1. W ten sposób całość upraszcza się do:

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

Operator >>= jest przypisaniem złożonym , który przesuwa swój lewy operand w prawo o liczbę bitów podanych przez prawy operand i zwraca wynik. W tym przypadku właściwy operand a[1] zawsze ma wartość 1, więc jest odpowiednik:

while( a[0] >>= 1 )

Lub równoważnie:

while( a[0] /= 2 )

Wartość początkowa a[0] wynosi 10. Po przesunięciu w prawo raz, staje się 5, następnie (zaokrąglenie w dół) 2, następnie 1 i wreszcie 0, w którym momencie kończy się pętla. W ten sposób ciało pętli jest wykonywane trzy razy.

 461
Author: Ilmari Karonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:34

Jest to jakiś dość niejasny kod dotyczący digraphs, mianowicie <: i :>, które są alternatywnymi tokenami odpowiednio dla [ i ]. Istnieje również pewne wykorzystanie operator warunkowy. Istnieje również Operator zmiany bitów, właściwe przypisanie zmiany >>=.

To jest bardziej czytelna Wersja:

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

I jeszcze bardziej czytelną wersję, zastępując wyrażenia w [] wartościami rozstrzygnęli na:

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

Zastąpienie a[0] i a[1] ich wartości powinno ułatwić ustalenie, co robi pętla, tj. odpowiednik:

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

, który po prostu wykonuje (integer) dzielenie przez 2 w każdej iteracji, tworząc sekwencję 5, 2, 1.

 67
Author: juanchopanza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-26 18:56:31

Przejdźmy do wyrażenia od lewej do prawej:

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

Pierwszą rzeczą, jaką zauważyłem, jest to, że używamy operatora trójdzielnego z użycia ?. Więc podwyrażenie:

0xFULL ? '\0' : -1

Mówi " Jeśli 0xFULL jest niezerowe, zwróć '\0', w przeciwnym razie -1. 0xFULL jest szesnastkowym literałem zunsigned long-long sufiksem - co oznacza, że jest szesnastkowym literałem typu unsigned long long. To jednak nie ma znaczenia, ponieważ 0xF może zmieścić się wewnątrz zwykłego liczba całkowita.

Ponadto operator trójdzielny przekształca typy drugiego i trzeciego terminu na ich wspólny typ. {[9] } jest następnie konwertowane do int, co jest po prostu 0.

Wartość 0xF jest znacznie większa od zera, więc przechodzi. Wyrażenie staje się teraz:

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

Następny, :>jest } digraf . Jest to konstrukcja, która rozszerza się do ]:

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

>>= jest podpisanym prawym operatorem przesunięcia, możemy go spacji z a, aby jaśniej.

Ponadto, <: jest digrafem, który rozszerza się do [:

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

0X.1P1 jest literałem szesnastkowym z wykładnikiem. Ale bez względu na wartość, !! wszystkiego, co jest niezerowe, jest prawdziwe. 0X.1P1 jest 0.125 które jest niezerowe, więc staje się:

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

>>= jest podpisanym prawym operatorem zmiany. Zmienia wartość swojego lewego operandu, przesuwając jego bity do przodu o wartość po prawej stronie operatora. 10 w binarnym jest 1010. Więc oto kroki:

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

>>= zwraca wynik swojej operacji, tak długo jak przesunięcie a[0] pozostanie niezerowe za każdym razem, gdy jego bity zostaną przesunięte w prawo o jeden, pętla będzie kontynuowana. Czwarta próba to miejsce, w którym a[0] staje się 0, więc pętla nigdy nie jest wprowadzana.

W rezultacie ? jest drukowany trzy razy.

 41
Author: 0x499602D2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-30 02:41:41