Кресты / Говнокод #10934 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
void a() 
{
}
 
void b()
{
  return a();
}

Компилится.
http://ideone.com/8eP1w

Запостил: HaskellGovno HaskellGovno, (Updated )

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

  • Это моё говно, которое я час назад выложил на ГД.ру.
    Я проверял, можно ли для процедур делать то же, что и для функций - возвращать результат вызова другой функции. Мало ли, он скажет, что для пустых результатов это недопустимо.
    Ответить
    • Где здесь?!
      И процедур там нет, есть только функции. Эту надо переименовать в helloUB
      Ответить
      • Почему убэ? Надо добавить в a() какое-то действие (вывод текста) и проверить, убэ это или не убэ.
        Ответить
        • никакого ub
          все вызовется как положено
          обычное дело
          странно, что это стало сюрпризом
          Ответить
            • вы так говорите, как будто вас смущает и обычный return; из войдовской функции - типа же тоже "вернуть"
              Ответить
              • В том-то и дело, что в процедурах сделано исключение - можно писать return без значения. А тут процедура - и return со значением!
                Ответить
                • return a(); в данном случае эквивалентно a(); return;
                  первая запись удобнее, когда происходит
                  if (smth)
                     return a();
                  что явно симпатичнее, чем
                  if (smth) { 
                     a(); 
                     return;
                  }
                  Ответить
                  • На самом деле мне это надо для
                    #if smth
                    #define MY_COOL_TYPE void
                    #else 
                    #define MY_COOL_TYPE int
                    #endif
                    ...
                    MY_COOL_TYPE a() 
                    {
                    ...
                    }
                     
                    MY_COOL_TYPE b()
                    {
                      return a();
                    }
                    Ответить
                        • ну если твой гипотетический пример, то
                          template <class R>
                          R a() {...}
                          
                          template <class R>
                          R b() { return a<R>(); }

                          но в подавляющем большинстве случаев шаблонные типы выводятся из аргументов (которых у тебя нет) и потому явного указания не требуют
                          Ответить
                          • И как это применить к моему случаю?
                            Вот смотри, под маздайкой главфункция возвращает int, под андрюшкой void, дальше, внутри главфункции сразу вызвается return RunApp(APP_PARAMS), которое имеет свою реализацию для и андрюшки, и маздайки. Тут на шаблонах не сделать, только препроцессором.
                            Ответить
                            • главфункция - это main?
                              или ты мне про какие то непреодолимые разногласия в api?
                              они должны разруливаться api-wrapper, да, не без препроцессора - чтобы совсем сокрыть чужеродный код от компилятора, который его не поймет, но на уровне использования всё должно выглядеть единообразно, тонкости реализации (и в т.ч. что конкретно возвратит тот или иной апи вызов) не должны вылезти за интерфейс этого враппера
                              Ответить
                              • В главном файле проекта препроцессора нет.
                                На уровне использования всё выглядит как просто возврат значения, возвращаемого внутренней функцией.
                                Для андрюшки это значение имеет тип void.
                                Ответить
                                • для неконсольного приложения на С++ код возврата имеет очень мало смысла, поэтому ты как-нибудь переживёшь ворнинг компилятора про void main и примешь его за данность
                                  ну а RunApp сможешь объявить как void на обеих платформах

                                  или тривиальней:
                                  http://ideone.com/e0WnS
                                  Ответить
                                  • Во-первых, работает и так, и без предупреждений от компилятора. А во-вторых, в студии void WinMain(всякая херня) вообще не скомпилируется:
                                    c:\Users\TarasB\Documents\Visual Studio Projects\Test_Krestoproject\Test_Krestop roject.cpp(4): error C2371: 'WinMain' : redefinition; different basic types
                                    c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WinBase.h(1 574) : see declaration of 'WinMain'
                                    "Или тривиальнее" - и как это написать кроссплатформенно, на засунув препроцессор поглубже?
                                    Ответить
                                    • Т.к. у вас RunApp(APP_PARAMS) имеет свою реализацию для и андрюшки, и маздайки (и нужная видимо выбирается препроцессором), то предлагаю нужный для текущей платформы main тоже выбрать препроцессором.

                                      Или даже, возможно, подумать о двух модулях main_android и main_win, из которых на каждой платформе будет собираться только один.

                                      Если же runApp отличаются только возвращаемым значением - то пускай runApp всегда возвращает int. А выбранный препроцессором main уже разберется - возвращать ему это значение или просто выкинуть его.
                                      Ответить
                                      • Да, главная функция совсем разная на каждой платформе. Но делать всю функцию одним макросом я не могу, так как где-то в ней же должны быть места, определяющие обработчики событий. Можно сделать макрос с параметрами, но это не так удобно, как функция с параметрами - для функции подсказка наглядее высветит типы и имена.
                                        И требование - отсутствие препроцессора в главном файле.
                                        Ответить
                                        • Вот так не устроит?
                                          [code=c++]
                                          #ifdef WE_ARE_ON_ANDROID
                                          int runApp(...args...) {
                                          ... runApp for android ...
                                          }
                                          void main()
                                          {
                                          runApp(...);
                                          }
                                          #else
                                          int runApp(...args...) {
                                          ... runApp for win32 ...
                                          }
                                          int main()
                                          {
                                          return runApp(...);
                                          }
                                          #endif
                                          > И требование - отсутствие препроцессора в главном файле.
                                          А в чем причина, если не секрет?

                                          ПыСы: если они совсем разные - ну может правда сделать 2 разных файла, которые будут выбираться системой сборки?
                                          Ответить
                                          • Твоё решение переносит препроцессор в главный файл.
                                            Это значит, что каждый раз при написании новой программы я буду по новой городить вот это вот #if и так далее...
                                            И препроцессор в главном файле это уродливо и ваще. Вот я даже руководство "как использовать SDL под андрюшку читаю", и там пишут "а для андрюшки главный файл надо будет слегка переписать вот так-то", но это же тьфу, криво как-то.
                                            Ответить
                                            • А кто мешает запилить несколько реализаций главного файла для разных платформ (заняться этим 1 раз). Затем оформить их в виде либы, или, возможно, тупо копировать в новые проекты без изменений. В новых проектах достаточно будет запиливать новый int runApp()...
                                              Ответить
                                              • Запилю я файл с главной функцией. Запихну я тело функции (полностью) в макрос DO_ALL.
                                                И как этот макрос вызывать? Где обработчики выставлять?
                                                Ответить
                                                  • Ну который содержит полностью и объявление и тело главной функции.
                                                    Ответить
                                                    • > Ну который содержит полностью и объявление и тело главной функции.
                                                      За каким х.ем он его содержит?
                                                      // main_android.cpp
                                                      #include "app.h"
                                                      void main()
                                                      {
                                                          App app;
                                                          app.run();
                                                      }
                                                      // main_windows.cpp
                                                      #include "app.h"
                                                      int WINAPI WinMain(...всякий хлам...) {
                                                          App app;
                                                          return app.run();
                                                      }
                                                      // app.h
                                                      class App {
                                                      public:
                                                          int run();
                                                      };
                                                      // app.cpp или же app_android.cpp и app_win.cpp по отдельности
                                                      int App::run() { ... }

                                                      Какие файлы компилировать, а какие нет - настроите в проектах\мейкфайлах\что-там-у-вас.
                                                      Ответить
                                                      • А, выставляете обработчики через глобальные переменные, которые надо самому же и создавать в главном файле. Мне это решение тоже не понравилось, опять же по причине отсутствия самодокументируемости (как и решение с макросом с параметрами).
                                                        Ответить
                                                        • > выставляете обработчики через глобальные переменные
                                                          Обработчики чего?
                                                          Ответить
                                                          • Обработчики событий, то есть то, что отличает одну программу от другой. Без них все программы были бы абсолютно одинаковыми - показывали бы пусток окно и закрывались по крестику.
                                                            Ответить
                                                            • А что они делают в main? Я думал они уже разруливаются в run() независимо от текущей платформы...
                                                              Ответить
                                                              • А, всё, понял. То есть архитектура получется как у меня, только наоборот. Да, тоже вариант.
                                                                Ответить
                                        • на каждой платформе заводи свой файл в котором объявляй нужный на этой платформе main. при компиляции файлы лишних платформ не включаешь в набор компилирующихся и линковщик сам разберется.
                                          Ответить
                                          • Мы уже обсудили этот вариант, особых преимуществ над своим не вижу, чтобы менять.
                                            Ответить
                                      • > А выбранный препроцессором main уже разберется
                                        если уж делать два файла - пускай разбирается система сборки (даже в том же студийном проекте можно для разных конфигураций задать компилировать этот cpp или исключить из построения)
                                        Ответить
                                        • Два файла и система сборки? Полностью засунуть тело Main в препроцессор я не могу, потому что я должен где-то задавать обработчики, и желательно не в параметрах макроса.
                                          Ответить
                                          • > Полностью засунуть тело Main в препроцессор я не могу
                                            тебе нужно main_win.cpp, main_android.cpp, app_win.cpp, app_android.cpp
                                            последние два отвечают единому интерфейсу app.hpp (если и интерфейс app у тебя разный, то опять же app_{win,android}.hpp - по мере распухания различий я бы посоветовал завести параллельные папки win32/ и android/, куда класть уже нормальные main.cpp, app.cpp, etc - в студии есть фильтры, которые можно вручную заводить так, чтобы они соответствовали структуре папок)
                                            в системе сборки для конфигурации win32 для *_android.cpp выставляешь "исключить из построения"
                                            done
                                            Ответить
                                        • Ну я собственно об этом писал строчкой выше процитированной фразы.
                                          Ответить
      • Тарас же! Величайший паскалист нашего времени. Отсюда и процедуры...
        Ответить
    • >Это моё говно, которое я час назад выложил на ГД.ру.
      Быстрое нынче Гумно пошло - резкое как понос.
      Ответить
  • g++-4.5 -Wall -Wextra -pedantic-errors

    gcc-4.5 -std=gnu99 -Wextra -Wall -pedantic-errors
    error: ISO C forbids ‘return’ with expression, in function returning void
    Ответить
    • да, не первый случай, когда ограничения стандарта снисходительно игнорируются компиляторами в пользу людей
      С11-n1548:
      6.8.6.4 The return statement
      Constraints
      1. A return statement with an expression shall not appear in a function whose return type is void. A return statement without an expression shall only appear in a function whose return type is void.

      стандарт С++ в этом плане более мягкий:
      6.6.3 The return statement
      3 A return statement with an expression of type “cv void” can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller.
      Ответить
      • В с++ видимо ослабили проверку для удобства разработки шаблонов (не нужно делать отдельную специализацию под возвращаемый void)?
        Ответить
        • возможно, в том числе
          мне кажется вполне здравым пользоваться таким return a(); даже не в шаблонах и не стыдиться этого
          Ответить
  • Одна из проблем языков, делающих упор на statements, а не на expressions - пресловутый void. Мне кажется, наличие типа Unit делает язык более последовательным и удобным для понимания и использования. В жабе вон для дженериков придумали класс Void без экземпляров (только null только хардкор), который выглядит как костыль.
    Ответить
    • так уж сложилось исторически
      да и не факт, что возможность получения вычисленного значения из if/case, for/while/do врядли бы сделала с++ более
      > удобным для понимания
      Ответить
    • Ну void в с++ отличается от unit type только тем, что нельзя описать переменную, поле или аргумент функции типа void. Такая возможность, конечно, была бы удобна в шаблонах, а в остальном коде разница, имхо, не заметна (все равно операций кроме присваивания и, возможно, сравнения, всегда возвращающего true, над ним не было бы).
      Ответить
    • >В жабе вон для дженериков придумали класс Void без экземпляров (только null только хардкор), который выглядит как костыль.
      Сучата. Тоже ощущение костыльности и бесполезности типа из-за небходимости возврата этого самого null.
      Ответить
  • Возможность делать такой return - специфическая фича С++, помогающая, в частности, в написании generic кода (т.е. шаблонного кода). В С такое запрещено, что, кстати, иногда мешает.
    Ответить

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

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8