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

    +125

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    int function(void) {
        static int i, state = 0;
        switch (state) {
            case 0: /* start of function */
            for (i = 0; i < 10; i++) {
                state = 1; /* so we will come back to "case 1" */
                return i;
                case 1:; /* resume control straight after the return */
            }
        }
    }

    Нестандартное применение свитча.
    Тут оно нафиг не нужно.
    Источник: http://www.gamedev.ru/code/forum/?id=142536

    Запостил: TarasB, 09 Января 2011

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

    • вообще-то этот код даже и работать не будет: компилер моментально выдаст ошибку:

      "case 1" - не видим в данном контексте...
      Ответить
      • Я где-то на Википедии видел подобный код, кстати.
        Видимо, при каких-то настройках в каком-то древнем стандарте такое можно было.
        Ответить
        • Код абсолютно по стандарту написан. Хотя и выносит мозг))))
          А вообще.
          http://ru.wikipedia.org/wiki/%D0%A3%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1% 81%D1%82%D0%B2%D0%BE_%D0%94%D0%B0%D1%84% D1%84%D0%B0
          Ответить
      • ОПА О_о оно работает... тяк... пошёл разбираться что к чему :(
        Ответить
      • А почему бы такому не работать?
        i всегда определено. Если прыгаем внутрь цикла, то просто подходим к концу итерации.
        Ответить
        • Я только не понимаю, зачем это так делать?
          Если state 0, то меняем на 1, иначе, если i меньше 10, увеличиваем i. Нахера выпендриваться?
          Ответить
          • Может кого-то хотели просто напугать.
            Или надрезать шаблон, как вот первому комментатору.
            Бессмысленно
            Ответить
          • там при изменении стейт = 1, оно сразу натыкается на рет - так что по циклу не ходит...
            - там, я так полагаю, функция рассчитана на циклическое использование или для перерисовок... - как вариант можно использовать для подсчёта количества перерисовок :)

            тут нужно доработать:
            int function(void) {
                static int i, state = 0;
            
            _switch:
                switch (state) {
                    case 0: /* start of function */
                    for (i = 0; i < 15; i++)
                    {
                        state = 1; /* so we will come back to "case 1" */
            
                        goto _switch;   /* выпрыгиваем на проверку свича  */
            
                        return i;
                        case 1:; /* resume control straight after the return */
                    }
                }
            }


            теперь цикл внутри - работает =Ъ
            Ответить
            • оно последовательно возвращает 0..9, а потом пустоту. (в #5186)
              тут — 14, void, void...
              Ответить
              • Минусотролли набигают!
                Ответить
                • и правильно делают, я считаю, а то развели тут тред добра...
                  Ответить
                  • "Тред добра" - это как раз результат того, что набежали минусотролли и устроили "тред зла" и каждый "добропорядочный" гражданин, имеющий в своём составе армию ботов - решил исправить ситуацию. :D
                    Ответить
                  • анально ущемленное хомячьё, methinks, бурлят-с
                    Ответить
                • Собственно для комментариев вообще плюсоминусы не нужны здесь. Ну может быть только если простыни троллобреда на полэкрана прятать. Даже рейтинга банального нет лучших высказываний.
                  Ответить
        • почему не работать:
          -- как-то стрёмно, стало, что можно было прям в тело цикла запрыгнуть, и чтобы такое работало :(

          и честно, - даже удивлён был, что ни слова не сказал компилер, что так делать не хорошо... О_о
          Ответить
        • >А почему бы такому не работать?
          Хотябы потомучто этот код не потоковобезопасный, тк использует общие для разных потоков static переменные (если, кончно, это не входило в планы разработчика).
          К тому же после завершения цикла перестаёт возвращать из функции вообще какие либо значения. После завершения цикла просто возвращает случайный мусор.
          Ответить
          • Ездить на машинах по разных рядах тоже опасно, но водителя это не волнует.

            Ну, тут я не сильно знаком с тем, что будет возвращаться функцией, если ничего не будет возвращаться в её теле. Предположил, что она возвращать будет что-то на подобии указателя с недотипом void
            Ответить
            • >Ездить на машинах по разных рядах тоже опасно, но водителя это не волнует.
              Какой-то неудачный пример.
              Ответить
              • машинка => программа
                ряд => поток
                водитель => компилятор
                Ответить
                • Где Вы видели, что-бы программа в разных потоках "ездила"? Вы перепутали потоки с процессами?
                  Ответить
                  • >Где Вы видели, что-бы программа в разных потоках ездила?
                    Насколько я знаю, потоки порождаются процессами.
                    Ответить
                    • Ну теперь расскажите всё, что знаете из школьного курса о потоках и процессах. :D
                      Ответить
                      • Не в той школе я учился, где бы такое рассказывали..
                        Ответить
                        • Кому было интересно - те сами читали.
                          А то расскажите мне курс, запишите за меня в тетрадку, покажите видеокурс и запомните за меня...
                          Ответить
                • Ну ездят машины в разных рядах, что здесь опасного?

                  Опасны столкновения между машинами.
                  static - это и есть то самое "столкновение" между потоками.
                  Ответить
                  • >Ну ездят машины в разных рядах, что здесь опасного?
                    по разным рядам.
                    >Опасны столкновения между машинами.
                    Взаимоисключающие параграфы?
                    Ответить
                    • Не хочу с Вами больше спорить. Наверное, мы говорим на разных языках. Пускай рассудят другие.
                      Ответить
            • >я не сильно знаком с тем, что будет возвращаться функцией
              Функция вернёт случайный мусор, тот, что остался в регистре eax, если не использовать return.

              В данном коде есть случаи, когда return не вызывается. Тогда мы получим мусор.

              Что-бы стало лучше - нужно state=0 после цикла поставить и "goto" на начало функции.
              Ответить
            • >Ездить на машинах по разных рядах
              Предложние не согласовано.
              Ответить

    • Ответить
    • Вау! Кривая эмуляция C#'овского yield в С++!
      Ответить
      • В C# эта конструкция (по смыслу отличается), но будет выглядеть так:
        IEnumerable<int> function()
                {
                    int i;
                    for (i = 0; i < 10; i++)
                        yield return i;
                }
        Ответить
    • Я бы сказал что это нестандартное(ненужнoе) применение конечного автомата.
      Ответить
      • Это обычная корутина. (Традиционный спутник современного функционального программирования.)
        Корутины (Coroutine) позволяют прерывать вычисления функции с возвратом значения (return) и продолжать с того же места, на котором остановились.
        В C# для этого используется оператор yield.

        Пожалуй, в данном говнокоде сделано не очень аккуратно, но смысл передаёт.

        Интересно, существуют ли альтернативные реализации корутин на С++?
        Ответить
        • А вот и пример реализации корутин на C/C++:
          http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
          Ответить
        • Вообще, ещё есть реализации корутин на C++ через fiber и через Save/Load ThreadContext.
          Ответить
        • Естественно, взамен С++, лучше применять для реализации паттерна корутин более подходящие языки, которые поддерживают его на уровне синтаксиса и семантики.
          Ответить
          • А мне проще каждую задачу раздробить на кванты действия и запоминать номер текущего кванта.
            Ответить
            • Иногда сложные конечные автоматы крайне удобно делать через корутины. При этом может значительно сокращаться код.
              Ответить
        • Для сопрограммы нужен отдельный стек. Это не вписывается в архитектуру C и C++.
          Ответить
    • хороший ориджинал. очень хороший.
      давно ничего подобного на гк не было - все окупировало пхп.
      Ответить
    • Прикольно конечно сперва, но поразобравшись понимаешь, что это просто бессмысленное нагромождение ничего не делающих конструкций, которое вернет 0. Примечательно лишь то, что эта функция обманывает компилятор, который выдает предупреждение, что функция ничего не возвращает, хотя на самом деле она всегда возвратит 0. case 1: естественно никакого управления не возвращает (тестировалось на bcb)/
      Ответить
      • Может быть на каком-нибудь другом компиляторе (и скорее всего это недоработка разработчиков) оно и пройдет, но по стандарту языка такое работать не должно (смысле возврат управления после return).
        Ответить
      • >просто бессмысленное нагромождение ничего не делающих конструкций
        Это совершенно не так. Этот паттерн, с некоторой натяжкой, называется корутина и я выше это описал в http://govnokod.ru/5186#comment68330

        >по стандарту языка такое работать не должно
        Должно.

        Это функция при каждом вызове вернёт следующее значение переменной i из цикла (и так от 0 до 9).
        Тоесть Console::Write(function()) выведет на экран 0.
        Следующий вызов Console::Write(function()) выведет на экран 1 и так до 9.
        Дальше там в коде косяк, тк не возвращается зачение return'ом, но с варнингом скомпилируется и будет возвращать мусор.
        Ответить
        • Дк ну и че: i, state же объявлены как static, никакого "чудесного" возврата управления в таком виде как это предоставил автор я не вижу. И вообще я немного про другое подумал под выражением "resume control straight after the return". При повторном вызове все закономерно происходит. Уж объясните мне пожалуйста чего вы такого необычного нашли в этой бессмысленной конструкции - я лично ничего не вижу.
          Ответить
          • >его вы такого необычного нашли
            В С++ при даной реализации она почти ничего не стоит.
            Ответить
            • Чего я и говорил, да я согласен, что немножко неправильно высказался, но по комментам в коде я подумал, что автор хочет показать совсем другое.
              Ответить
              • Автор показал лишь идею, которую можно расширять далее, например через препроцессор Си.

                Но всё же лучше этого не делать, а воспользоваться более подходящими для этого инструментами, чем Си.
                Ответить
                • > Автор показал лишь идею
                  Идею я теперь понял
                  > Но всё же лучше этого не делать
                  А я и не собирался
                  Ответить
        • Под тем, выражение, что "эта функция всегда вернет 0" я имел ввиду ее первый вызов. А так согласен, что при следующем она будет возвращать другое значение. Я честно говоря не сразу понял вообще не понял какой смысл у данного кода и сейчас толком понять не могу. При каких обстоятельствах тут будет возврат управления после return? Я лично не могу понять.
          Ответить
          • >говоря не сразу понял вообще не понял
            >понять не могу
            >не могу понять
            Просто загуглите про корутины или хотябы сходите по моей ссылке, в которых есть кривенькая рализация всё тех же корутин на чистом Си.
            Ответить
            • Да я знаю, что такое сопрограмма. Я имею ввиду другое, а именно, что автор утверждает (как я уже сейчас понял), что управление будет передано после retrun, это не так (передано оно конечно будет туда, но не сразу), для этого достаточно вставить что-нибудь перед switch'ем. Конечно может быть при такой реализации компилятор и оптимизирует данный код должным образом, но вообще это не верно.
              Ответить
              • >для этого достаточно вставить что-нибудь перед switch'ем
                Ни кто с этим и не спорит. Автор расчитывает, что функция со свитча начинается.

                >компилятор и оптимизирует данный код
                Оптимизация тут не причём. Этот код - лишь эмуляция начала функции с return через свитч.

                Если ссылку так и не нашли, то приведу снова, сходите:
                http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
                Только там про корутины из текущего говнокода написано ближе к середине.
                Ответить
                • > Оптимизация тут не причём
                  Для говнокода - да.
                  > Если ссылку так и не нашли
                  Да я вас отлично понимаю, не надо думать, что я не знаю, что такое сопрограмма. Я вообще как бэ другое хотел сказать.
                  Ответить
                  • >Я вообще как бэ другое хотел сказать.
                    Я Вас послушаю. Что Вы хотели сказать?
                    Ответить
                    • А вы вообще читали мои сообщения? Посмотрите повнимательнее.
                      Ответить
                      • Ну да. Вы раза 4 сказали, что не можете понять. И раза 2, что: знаете, что такое корутины (сопрограмма).
                        Попробуйте повторить, возможно я не всё понял.
                        Мне показалось, что не всё внятно расписано, извиняюсь... :-[
                        Ответить
                        • > При каких обстоятельствах тут будет возврат управления после return?

                          > Я имею ввиду другое, а именно, что автор утверждает (как я уже сейчас понял), что управление будет передано после retrun, это не так (передано оно конечно будет туда, но не сразу), для этого достаточно вставить что-нибудь перед switch'ем

                          >>для этого достаточно вставить что-нибудь перед switch'ем
                          Ни кто с этим и не спорит. Автор расчитывает, что функция со свитча начинается.

                          Теперь понятно?
                          Ответить
    • Те, кому хочется "Въ***ал всем по минусу" (цитата от Компренда) - Вам суда:
      http://govnokod.ru/5153
      Ответить
      • Да я заманался в 5 виртуалов с генератором зла воевать, народ, помогайте.
        Ответить
        • Вы несколько нарушили баланс рейтингов постов, впрочем спасибо. :)
          Ответить
    • Не пойму, что все так удивились, увидев такое использование свитча?

      Школоте для общего развития: http://ru.wikipedia.org/wiki/Устройство_Даффа
      ;)
      Ответить
      • > в то время работал на Lucasfilm
        Как в мире С всё... эээ, демократично, хоть бы одна знаменитость имела профильное образование и после защиты устроилась работать с компьютерами...
        Ответить
        • Учил информатику, затем оптимизировал альфа-смешивание. По-моему, к битикам ближе не подойдешь.
          Ответить
          • > альфа-смешивание
            альфа-наложение, facepalm.sgi

            вообще у него даже публикация есть, хотя непонятно чего там исследовать, что характерно, тогда работал на мамашу Белл, как и остальные
            Ответить
            • В публикации вывод начинается с того, что фреймбуфферы неплохо бы побольше делать)
              Ответить
              • хех, правильно что я не стал заморачиваться и искать тескт :)
                Ответить
      • Я уже привёл ссылку, в том числе и на Duff's device в посте выше:
        http://govnokod.ru/5186#comment68340
        Так, что думаю удивляются только единицы.

        В любом случае даффдевайс, как и этот код - говно говном.
        Ответить
      • Да, я на него и хотел найти ссылку.
        Его тоже надо сюда запостить. Бесполезная конструкция, которой зато можно троллить паскалистов (или сишников, смотря как её преподнести).
        Ответить
    • struct _func {
        _func() { index = 0; }
      
        size_t operator()() 
        {
          while(index < 10)
            return index++;
        }
      private:
        size_t index;
      };

      цппешники не ебут себе мозги

      _func function;
      while(1)
      std::cout << function();
      Ответить
      • Хороший метод (с точки зрения идеи) для С++. :)
        Ответить
      • Из проблем:
        1)Для многопоточных приложений придётся просить (комметарием) создавать функциональный объект в стеке.
        2)Будь код чуток сложнее, например:
        int operator()() 
          {
            int a=...;
            while(index < 10)
            {
              ...;
              int b=f(a);
              return f2(index++, b);
          }
        - ваш код уже работать не будет. В оригинальном коде управление передаётся сразу к return при повторном входе в функцию.

        Впрочем, для данного конкретного случая это намного лучше приведённого выше говнокода 5186. :)
        Ответить
        • >>1)Для многопоточных приложений придётся просить (комметарием) создавать функциональный объект в стеке.

          нет. могут создавать где угодно, главное, чтоб не было совместного использования одного объекта (каждый объект имеет свое состояние).


          >>ваш код уже работать не будет. В оригинальном коде управление передаётся сразу к return при повторном входе в функцию.

          это костыль, созданный для того, чтобы избежать return
          Ответить
          • >могут создавать где угодно
            А потом совершенно случайно не заметете, как станете использовать один из объектов в нескольких потоках. ))
            Ответить
    • Все понятно.
      При первом входе возвращает 0, потом 1, потом 2 и тд до 9.
      Мне понравилась идея - первый раз подобное встретил =)
      Ответить
    • Блять, я дочитал комменты, а вот брат ага
      Ответить
    • Какой же пиздец.
      Ответить
      • Это кривоватый прототип сишного async/await. Ну или yield.

        Контекст пропихнуть, макросом обмазать и вполне практично.
        Ответить

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