Что такое оператор>= в C?


данный коллегой как головоломка, я не могу понять, как эта программа C на самом деле компилируется и запускается. Что это такое >>>= оператор и странный 1P1 литерал? Я протестировал в Clang и GCC. Нет никаких предупреждений и выход "???"

#include <stdio.h>

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

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

    return 0;
}
3 287

3 ответа:

строку:

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

содержит орграфы:> и <:, что переводится как ] и [ соответственно, так что это эквивалентно:

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

в прямом 0xFULL это то же самое, что 0xF (который является наговор на 15); the ULL просто указывает, что это unsigned long long литерал. В любом случае, как логическое это правда, так 0xFULL ? '' : -1 оценивает в '', который является символьный литерал чье числовое значение просто 0.

между тем, 0X.1P1 это шестнадцатеричный литерал с плавающей запятой равна 2/16 = 0.125. В любом случае, будучи ненулевым, это также верно как булево, поэтому отрицание его дважды с !! снова производит 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 ? '' : -1 ] >>= a[ !!0X.1P1 ] )

и даже больше читаемая версия, заменяющая выражения в [] для значений, которые они разрешают:

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

замена a[0] и a[1] для их значений должно быть легко понять, что делает цикл, т. е. эквивалент:

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

который просто выполняет (целочисленное) деление на 2 в каждой итерации, производя последовательность 5, 2, 1.

давайте пройдемся по выражению слева направо:

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

первое, что я замечаю, что мы используем тернарный оператор от использования ?. Итак, подвыражение:

0xFULL ? '' : -1

говорит: "Если 0xFULL не равно нулю, возврат '', иначе -1. 0xFULL - это шестнадцатеричный литерал с беззнаковый длинный-длинный суффикс - означает, что это шестнадцатеричный литерал типа unsigned long long. Это действительно не имеет большого значения, хотя, потому что 0xF может поместиться внутри обычного целого числа.

кроме того, тернарный оператор преобразует типы второго и третьего членов в их общий тип. '' затем преобразуется в int, который является 0.

значение 0xF намного больше нуля, поэтому он проходит. Выражение теперь выглядит так:

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

далее :> это диграф. Это конструкция, которая расширяется до ]:

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

>>= является ли подписанный оператор сдвига вправо, мы можем поместить это из a чтобы было понятнее.

кроме того, <: - это орграф, который расширяется к [:

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

0X.1P1 - это шестнадцатеричный литерал с показателем степени. Но независимо от значения,!! все, что не равно нулю, верно. 0X.1P1 и 0.125 который не равен нулю, поэтому он становится:

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

The >>= является подписанным оператором сдвига вправо. Он изменяет значение своего левого операнд, смещая его биты вперед на значение с правой стороны оператора. 10 в двоичном виде это 1010. Итак, вот шаги:

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

>>= возвращает результат своей работы, так как пока смещение a[0] остается ненулевым для каждого раза, когда его биты сдвигаются вправо на единицу, цикл будет продолжаться. Четвертая попытка-это где a[0] становится 0, поэтому цикл никогда не вводится.

в результате ? напечатано три раза.