1. Си / Говнокод #13512

    +130

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    #include <stdio.h>
    
    int main()
    {
        int a = 5, b = 6;
        void* go;
        go = ( a > b )? &&true1: &&false1;
        goto *go;
    
          true1:
          {
            printf("%i > %i\n", a, b);
            goto next1;
          }
    
          false1:
          {
            printf("%i <= %i\n", a, b);
          }
    
        next1:
    
    
        a = 7;
        go = ( a > b )? &&true2: &&false2;
        goto *go;
        
          true2:
          {
            printf("%i > %i\n", a, b);
            goto next2;
          }
    
          false2:
          {
            printf("%i <= %i\n", a, b);
          }
    
        next2:
        return 0;
    }

    В GCC есть такой экстеншен http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
    Можно в goto передавать переменную и можно работать с адресами меток. В сочетании с тернарной условной операцией, этим можно заменить if

    Запостил: j123123, 30 Июля 2013

    Комментарии (58) RSS

    • Можно макрос IF накатать :)
      Ответить
    • > такой экстеншен
      Эта фича существовала давным-давно, еще до ANSI C, когда по земле ходили мамонты... Потом ее слава богу выпилили... Как оказалось - не до конца.

      P.S. Тут же можно еще и с адресной арифметикой постебаться - goto go+5;
      Ответить
    • Кстати, на аватарке изображен сумматор (младшими разрядами вниз)?
      Ответить
      • Да
        Ответить
        • А почему у него нет входа для переноса из минус первого разряда? Вдруг мне полуцелые числа придётся складывать?
          Ответить
        • Возникла идея: ко входам элемента, который в правом верхнем углу, параллельно подключить входы дополнительного элемента И, тогда получившийся четвёртый выход схемы будет называться «ОПА, НЕЖДАНЧИК» и отражать ситуацию, когда на выходах переноса двух полусумматоров одновременно возникнет единица.
          Ответить
          • > когда на выходах переноса двух полусумматоров одновременно возникнет единица
            Это на случай, если на одном из входов затесалась двойка? :)
            Ответить
      • Кстати, это же Граватар, можно и увеличить:
        http://gravatar.com/avatar/f3dd16071dd47ba61cd705ed6d200069?size=512
        Ответить
        • А я в профиле смотрел более-менее большую версию)
          Ответить
          • Кстати, я почему-то привык к другим обозначениям элементов. Вот нагуглил табличку перевода обозначений:
            http://rudocs.exdat.com/pars_docs/tw_refs/33/32904/32904_html_7235efb3.gif

            Всё у этих мерикосов через жопу. По мне легче запомнить, что & — это И, чем учить эти выпуклости и вогнутости.
            Ответить
    • Выходит, там можно и массив меток для интерпретатора сделать?
      И реализовать его как-то так:
      void *labels[0x100] = {label_0, label_1, label_2, ...}; // заполняем метками
      
      char* program = какой-то интерпретируемый код
      
      while(*program != COMMAND_EXIT){
        goto labels[*program];
      
        label_0:
          // что-то делаем
          goto end;
      
        label_1:
          // что-то делаем
          goto end;
      
        label_2:
          // что-то делаем
          goto end;
      
        ...
      end:
        ++program;
      }


      (А вообще, как обычно создатели интерпретаторов в этом случае поступают? Шитый код, switch или ещё что?)
      Ответить
      • показать все, что скрытоЗа это я и не люблю эти ваши консолечки, черт бы их подрал.
        Ответить
        • Причем тут консолечки? Консолечки можешь обосрать в соседнем треде, где чел рамки выводил на шарпе.
          Ответить
      • Ты изобрел bat.
        Ответить
        • Я не хочу bat, я хочу быстрый if в сишке :)
          Ответить
          • Пили функции, складывай указатели в массив :)
            Ответить
        • В бате можно переходить на метку, заданную переменной?
          Ответить
          • Хз, но там код выглядит примерно так.
            Ответить
            • С тем же успехом можно написать, что любой язык похож на любой (кроме Вайтспейса, разумеется), ибо содержит буквы и знаки препинания.

              В бате переход возможен только на фиксированную метку.
              Ответить
              • В бате ифов нормальных нет, или есть, но появились недавно, или выглядят как говно. Так что овер дохуя старых батников - именно спагетти с гото. Не знаешь - не трынди.
                Ответить
                • Где я трындил, что в классических батниках есть нормальные ифы? Где, в каком комментарии, в какой строчке?

                  Я писал о том, что GOTO %Variable% в батнике работать не будет. Только GOTO 1, только хардкор.
                  Ответить
                  • Ну а я написал, что код внешне будет похож на бат. Ты мне про Фому, а я тебе про Ерему.
                    Ответить
                    • В нижней части — да. А в верхней в бате будет пачка ифов, а в сишечке только goto labels[*program];
                      Ответить
              • Можно, я даже говномейк так делал

                set TARGET=all
                ...
                
                goto %TARGET%
                
                :all
                	...
                	
                :lib
                	...
                	
                :clean
                	...
                Ответить
                • А дефолт можно сделать?
                  Ответить
                  • Нет, вроде бы. Зато метки можно использовать с оператором call и даже передавать аргументы %)
                    Ответить
                • Действительно работает, плюс анонимбу. Странно, при предыдущем испытании у меня не получилось...

                  Осталось придумать, чем заменить массивы.
                  Ответить
                  • Кстати, где-то была статья про "библиотеку", которая каким-то жестоким образом реализует массивы в батниках (и обычные, и ассоциативные)
                    Ответить
                • http://en.wikipedia.org/wiki/Threaded_code#Development

                  Случайно наткнулся, теперь вот, хотя бы знаю, как называется.
                  Ответить
      • можно адреса функций хранить - тогда и аргументы получится передавать по-честному.
        Ответить
        • А можно, ради извращения, вернуть из функции структурку, содержащую указатель на метку и сохраненные регистры... и на основе этого запилить какой-нить call with current continuation или аналог питонского yield.
          Ответить
        • По идее, с ними будет медленнее. Скажем, реализуем инкремент "регистра" в виртуальной машине. Так бы это был переход, инкремент, переход, а тут функцию вызывать надо.
          Мне вот интересно, создатели интерпретаторов в этом случае сразу переходят на генерацию кода, пишут на ассемблере, или вызов функции не такой медленный по сравнению с тем, что в этой функции будет.
          Ответить
    • warning: welcome to 'goto hell'
      Ответить
    • int abs(int value)
      {
      static void * lbs[] = {&&POS,&&NEG};
      goto *lbs[((unsigned int)value) >> 31];
      NEG:
      return (~value)+1;
      POS:
      return value;
      }
      говновычисление говномодуля
      Ответить
      • А если value не 32 битное?
        Ответить
        • тогда надо по царски: int32_t и тд, либо свдиг на sizeof(value)*8-1, правда вдруг в байте не 8 бит. а (unsigned int) нафиг не нужен.
          Ответить
          • CHAR_BITS * sizeof(value) - 1 как-то так вроде это делается.
            Ответить
          • > а (unsigned int) нафиг не нужен
            Нужен. Иначе будет неопределенное стандартом поведение. Обычно - знаковое расширение, из-за которого будет вынут -1й элемент массива вместо первого ;)

            P.S. А, понял. unsigned int не нужен если value изначально беззнаковое ;)
            Ответить
            • value то знаковое, не пойму, пусть value однобайтовое и равно -7 то бишь 0xF9, при расширении со знаком пусть до 32ух бит тем самым movsb он станет 0xFFFFFFF9, сдвинем его со знаком на 31 бит, вместо новых битов будет вставать знаковый разряд, то есть в итоге снова получим единицу в младшем разряде. УБ получается при сдвиге на >31 бит, лично проверял у х86 и sh4 там разный эффект получается
              Ответить
              • > вместо новых битов будет вставать знаковый разряд, то есть в итоге снова получим единицу в младшем разряде
                В младшем то единицу, да. Но в остальных то тоже вылезет единица (т.к. число отрицательное и знаковый бит равен единице). А 0xFFFFFFFF это -1.

                > УБ получается при сдвиге на >31 бит
                А это другой уб уже. Здесь я имел в виду уб (или implementation defined, не помню уже), связанный со сдвигом отрицательного числа вправо.
                Ответить
                • ааа, вдруг подумал что написал а оказалось не написал, надо делать [(value >> 31) & 1]
                  Ответить
      • Я доигрался:
        gcc 1.c -O2 -S
        1.c: В функции «hardcore_abs»:
        1.c:3:5: внутренняя ошибка компилятора: Ошибка сегментирования

        Выдалось при сборке вот этого кода с оптимизацией:
        #include <stdio.h>
        
        int hardcore_abs(int value) {
            static void * dummy[] = { &&neg, &&pos };
            goto *(&&pos - 3 * (value < 0));
        neg:
            value = ~value + 1;
        pos:
            return value;
        }
        
        int main() {
            printf("%d\n", hardcore_abs(42));
            printf("%d\n", hardcore_abs(-100500));
            return 0;
        }
        P.S. На -O0 это даже работает...

        https://ideone.com/9FH225
        Ответить
        • выпили ветвление, они не уместны с данным гццизмом!
          Ответить
          • Пофиксил:
            int hardcore_abs(int value) {
                static void * dummy[] = { &&neg, &&pos };
                goto *(&&pos - ((value >> 31) & 3));
            neg:
                value = ~value + 1;
            pos:
                return value;
            }
            Концентрация UB'ов растет ;) На -O0 по-прежнему работает.
            Ответить
            • это даже не убэ, это просто пиздец - плясать от длины команды...)))
              Ответить
              • А еще можно цикл замутить (15 взято от балды, надо подбирать по длине тела+goto, чтобы выпрыгнуть на следующую строку):
                int i = 10;
                loop:
                // ... тело цикла ...
                goto *(&&loop + (i -->> 31) & 15);
                Ответить
              • goto *(&&pos - ((value >> 31) & 1) * (size_t)(&&pos - &&neg));
                А так?
                Ответить
                • а так теряется хардкор
                  Ответить
                  • Придумал, как с хардкором, но без УБ (за синтаксис не ручаюсь):
                    int calc_jmp(){
                        int value, adr1, adr2;
                        asm {
                            call l1
                            l1: pop eax
                            mov adr1, eax
                        }
                        value = ~value + 1;
                        asm {
                            call l2
                            l2: pop eax
                            mov adr2, eax
                        }
                        return adr2 - adr1 - 6;
                    }
                    int hardcore_abs(int value) {
                        static void * dummy[] = { &&neg, &&pos };
                        static int step = calc_jmp();
                        goto *(&&pos - ((value >> 31) & 1) * step);
                    neg:
                        value = ~value + 1;
                    pos:
                        return value;
                    }
                    Ответить
                    • Не факт, что компилятор соберет код одинаково ;) Поэтому, имхо, что 3, что такой расчет, все едино...

                      А еще тут вместо магической тройки возникла магическая шестерка ;)
                      Ответить
                      • > возникла магическая шестерка
                        Я старался! А ведь мог тупо написать разность между метками, тогда бы и магическая константа не понадобилась.
                        Ответить
    • http://graphics.stanford.edu/~seander/bithacks.html для истинных байтоёбов
      Ответить
      • http://www.amazon.com/Hackers-Delight-Edition-Henry-Warren/dp/0321842685?tag=s601000020-20
        Ответить
        • Мегавинрар. Есть книги, которые через пару 5 лет уже неактуальны, но эта - вечна.
          Одна из самых любимых, наряду с Конкретной математикой Кнута.
          Ответить

    Добавить комментарий