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

    0

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    void receivePtrs(void **);
    
    int main() {
    L:
      receivePtrs((void *[]){ &&L, 0, 0 });
    }

    что делает этот код?

    Запостил: ASD_77, 29 Августа 2021

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

    • а?
      Ответить
    • Непортабельное нестандартоговно не нужно.
      Ответить
      • Тут еще нужно заметить, что пробрасвание метки наружу функции это очень плохая идея т.к. таким образом можно получить метку от заинлайненой функции, и будет хуй знает что, если этой меткой воспользоваться даже внутри самой такой функции.

        У меня про это был говнокод https://govnokod.ru/22794 -> https://govnokod.ru/22794#comment384245 -> https://gcc.gnu.org/legacy-ml/gcc-help/2017-04/msg00051.html

        > the compiler treats labels similarly to automatic variables, meaning that their address is considered valid only until the function returns. Optimizations that clone functions need to duplicate labels, and that will break code that smuggles label addresses to outer frames. See PR 80053 comment 2 for a sample that gets "miscompiled": https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80053#c2

        Так что надо запрещать инлайн для такой хуйни.
        Ответить
        • Ну тогда это вообще бесполезная хуйня... Лучше свич юзать.
          Ответить
          • Это да, такими приколами лучше за пределами асма не заниматься. Кстати, где там еще кроме фортрана и гнутого расширения есть это "computed goto"?

            Можно и к инлайну прикрутить такое говно, если только хранить не непосредственный адрес, а дельту между "место где у нас goto туда или сюда" и "метка". И тогда можно относительно регистра "RIP" переходить по такому-то смещению. Важно только чтоб везде одинаковый кусок с равными "расстояниями" между метками и goto заинлайнивался.
            Ответить
    • Странно, что мой любимый прогрессивный g++ отказался кушать это. Зато вот clang согласился жрать.
      Ответить
      • Тем более странно, что это... гццизм. Видимо только в сишном режиме работает, а не в крестовом.
        Ответить
    • и как мне юзать эту говно-метку?
      Ответить
      • goto *ptr;
        Ответить
        • это я прыгну из функции на метку?
          Ответить
          • Прыгать по меткам можно только в пределах одной функции. Т.е. и ptr = &&L и goto *ptr и сама метка должны быть в одной функции. А вот хранить её адрес можно и где-то во внешнем контексте, никто не запрещает.
            Ответить
            • Теоретически можно выходить и за пределы, но тогда нужно вручную пердолить стек, чтобы данные не распидорасило.
              Ответить
              • Если уж настолько упарываться, то проще стек переключить как в boost::coroutine.
                Ответить
                • Кстати, вот тут я упарывался со стеком (гуеста восьмого, с которого я тогда писал, на «РУ» потёр Псор Слуцкер):
                  https://govnokod.xyz/_24763/#comment-390727

                  У меня там и && были, и аналог «computed goto» я наговнокодил с помощью патча стека.
                  Ответить
                  • Скопирую сюда пару упоротых примеров.

                    Цикл:
                    #include <stdio.h>
                    typedef struct {
                      int endValue;
                      void * startBody;
                    } loop_record;
                    
                    loop_record stack[1000];
                    int head = 0;
                    
                    void push(loop_record value) {
                        stack[head] = value;
                        head++;
                    }
                    
                    loop_record pop() {
                        head--;
                        if (head < 0) exit(255);
                        return stack[head];
                    }
                    
                    void _for(int * counter, int from, int to) {
                      void ** frame = __builtin_frame_address(0);
                      *counter = from;
                    
                      loop_record current;
                      current.endValue = to;
                      current.startBody = frame[1];
                      push(current);
                    }
                    
                    void _next(int * counter) {
                      void ** frame = __builtin_frame_address(0);
                      (*counter)++;
                    
                      loop_record current = pop();
                      if (*counter <= current.endValue) {
                        push(current);
                        frame[1] = current.startBody; // Эквивалент goto *startBody (на след. инструкцию после вызова _do)
                      }
                    }
                    
                    int main() {
                      int i;
                      _for(&i, 1, 5);
                        printf("Хорошо живёт на свете Винни-пух (%d).\n", i);
                      _next(&i);
                      printf("Оттого поёт он эти песни вслух.\n");
                    }
                    Ответить
                    • Свитч:
                      #include <stdio.h>
                      typedef struct {
                        void * ret;
                      } loop_record;
                      
                      loop_record stack[1000];
                      int head = 0;
                      
                      void push(loop_record value) {
                          stack[head] = value;
                          head++;
                      }
                      
                      loop_record pop() {
                          head--;
                          if (head < 0) exit(255);
                          return stack[head];
                      }
                      
                      void _switch(int counter, void ** labels) {
                          loop_record current;
                          current.ret = labels[0];
                          push(current);
                          void ** frame = __builtin_frame_address(0);
                          frame[1] = labels[counter];
                      }
                      
                      void _break() {
                          loop_record current = pop();
                          void ** frame = __builtin_frame_address(0);
                          frame[1] = current.ret;
                      }
                      
                      int main() {
                        void * jmpTable[] = {&&end, &&case_1, &&case_2, &&case_3};
                        _switch(2, jmpTable);
                          case_1:
                          printf("Первый багор.\n");
                          _break();
                          case_2:
                          printf("Второй багор.\n");
                          _break();
                          case_3:
                          printf("Третий багор.\n");
                          _break();
                        end:
                        printf("Всё!.\n");
                      }
                      Ответить
                    • > _for(&i, 1, 5);
                      > ...
                      > _next(&i);

                      Какой BASIC )))

                      Очень зачётное говно.
                      Ответить
                      • Это говно придётся ещё корректировать под те платформы, в которых коллконвеншен отличается.
                        Ответить
                      • Вроде должно и на вложенных циклах работать, для этого я и городил push и pop.
                        Ответить
                    • Кококококой багор )))
                      Ответить
              • > но тогда нужно вручную пердолить стек, чтобы данные не распидорасило.

                Подтверждаю.

                В приницпе можно прыгнуть внутрь функции, что-то выполнить, а потом вернуться обратно. А-ля GOSUB / RETURN.
                Ответить

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