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

    +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
    #include <stdlib.h>
     
    struct no_matter
    {
        int some_field;
    };
     
    struct matter *do_stuff(void)
    {
        struct no_matter *m = calloc(1, sizeof *m);
        return m;
    }
     
    int main(void)
    {
        struct no_matter *m = do_stuff();
        free(m);
        return 0;
    }

    Сегодня выполняю роль гумна. В сишке можно возвращать указатель на непонятно откуда взявшуюся необъявленную ранее структуру и код будет компиляться (ладно хоть пишет невнятные ворнинги, только благодаря им нашёл опечатку в одной букве в имени структуры в рабочем коде). Понятно, что все указатели одинаково числа, но всё равно как-то некрасиво. Хацкелисты негодуэ, даёшь монаду Ptr

    http://ideone.com/3SABHW

    Запостил: roman-kashitsyn, 27 Ноября 2012

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

    • Видимо, из разряда вызова функции без прототипа? Давать ошибку нельзя, приходится обходиться ворнингами.
      Ответить
    • не понял суть претензии
      структура объявлена до первого использования, calloc честно выделяет память, free честно удаляет её
      Ответить
      • > struct matter *
        > struct no_matter *
        calloc и free здесь не при чём, они просто отражают ситуацию, с которой я столкнулся.
        Я знаю, почему это работает, мне просто не нравится, что оно должно компилиться (теперь только -Werror, только хардкор).
        Ответить
        • вот теперь понял
          с первого раза и не углядишь даже
          Ответить
          • > с первого раза и не углядишь даже
            Вот и я о том же: ещё один отличный способ выстрелить себе в ногу.
            Ответить
            • поэтому сишкоблядский кастинг пойнтеров в мерзких крестах (да, Тарас?) был переделан в первую очередь
              как и использование необъявленных типов
              Ответить
      • Тип matter * до использования void * ?
        Ответить
      • Роман имел в виду неявный каст из no_matter* в matter*.

        я всегда буду обновлять тред перед отправкой комментария
        я всегда буду обновлять тред перед отправкой комментария
        я всегда буду обновлять тред перед отправкой комментария
        я всегда буду обновлять тред перед отправкой комментария
        Ответить
        • > я всегда буду обновлять тред перед отправкой комментария
          > я всегда буду обновлять тред перед отправкой комментария
          > я всегда буду обновлять тред перед отправкой комментария
          > я всегда буду обновлять тред перед отправкой комментария

          Каждый раз, когда не обновляешь - на 1 строчку больше дописываешь?
          Ответить
          • Надо каждый раз вдвое больше писать... А вообще надо бы замутить плагин к браузеру, который в момент отправки будет проверять, что страница изменилась, и предупреждать об этом.
            Ответить
            • Или нанять помошника, который будет бить по яйцам за каждую ошибку.
              Ответить
            • >...который в момент отправки будет проверять, что страница изменилась, и автоматически вставлять "я всегда..."
              Fixed.
              Ответить
    • Под определённым углом ссылка читается как ЗБАВНЙ
      Ответить
      • С утечками проблем нет: calloc знает, сколько он выделил памяти, free знает, сколько нужно удалить (обычно рядом с памятью под указателем лежит хедер с метаданными).
        Просто можно указателю на одну структуру присвоить указатель на другую, и сишка это съест.

        Видимо, Ритчи изобрёл Dynamic Typing задолго до того, как это стало мэйнстримом.
        Ответить
        • С утечками проблема в том, что не используется никакая парадигма для контроля за памятью кроме как "запомни, эта функция выделяет память, не забудь сам её удалить!". Насколько я знаю, в сишке не принято так делать и даже в стандартной библиотеке все функции со строками работают только с памятью, выделенной заранее.
          Ответить
          • > все функции со строками работают только с памятью, выделенной заранее
            Это возможно далеко не всегда. Например, если размер структуры не известен клиентскому коду (а в моём случае это верно чуть чаще чем всегда: клиенты работают с загадочным struct something *, не зная, что внутри).
            Экземпляры порождаются/уничтожаются с помощью allocate_something() / deallocate_something(), за правильный вызов отвечает клиент.
            Ответить
            • а винапишный способ?
              1) вызываем с параметром "длина моего буфера - 0", получаем "длина твоего буфера будет 25 см"
              2) вызываем с "длина моего буфера - 25 см", получаем "окей, теперь смотри сам свой буфер"
              Ответить
              • Именно так, добавлю ещё, что этот способ, когда память под структуру выделяет тот, кому она нужна, называется ещё "принцип Тараса Бульбы".
                Ответить
              • Я так понимаю, в качестве примера можно взять GetCurrentDirectory
                Что-то мне подсказывает, что это чревато race-conditions (необходимая длина буфера может поменяться между вызовами). Да и аллокации в куче это избежать не особо помогает, разве что через alloca, чревытый последствиями.
                Ответить
                • ну так каждый вызов возвращает либо ок, либо error_more_data, либо другую ошибку
                  если передать 0, вызов говорит error_more_data и говорит сколько (25 см)
                  вызываем с 25 см, вызов говорит error_more_data и говорит, что теперь надо 30 см
                  выделяем 40 см, вызов говорит "ок, записал 30 см"

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

                        Или записывают в свой локальный буфер и возвращает указатель на него.
                        Это вообще эпик фейлы стандартной сишной библиотеки (gets, sprintf, localtime, etc. - это ещё один пример того, когда не надо повторять за разработчиками api).
                        Ответить
                        • Ну что поделать. Про потоки тогда никто не думал. Если многозадачность и была - то на основе процессов. В то время все эти функции со скрытыми статик буферами были вполне адекватны, да еще и экономили драгоценные байтики, и не дрючили кучу.

                          Да и хакеров, в плохом смысле этого слова, тогда еще не было, а юзеры не вводили всякий хлам, поэтому gets и sprintf не вызывали ни у кого опасений...

                          Хорошее было время...

                          P.S. Еще доставляет имя функции creat(). Такое ощущение, что имена были ограничены пятью символами.
                          Ответить
                          • > creat(). Такое ощущение, что имена были ограничены пятью символами.
                            Некоторые линковщики не воспринимали больше шести.

                            Ken Thompson was once asked what he would do differently if he were redesigning the UNIX system. His reply: "I'd spell creat with an e."
                            Ответить
            • А если клиент хочет структуру не выделять, а работать со структурой на стеке?
              Ответить
              • Внутренности легковесных небольших структур (для которых постоянная аллокация неприемлема) у меня открыты, и функции обработки таких структур работают с указателями, предоставленными пользователями (например, эвенты потокового парсера или заголовки бинарных файлов).
                Для небольшого числа относительно крупных объектов (например, том псевдо-файловой системы) использую кучу. Кстати, в моём случае в качестве struct no_matter была struct test_suite, гуляющая между функциями.
                Ответить
        • Вот угар, все думают, что Роман Кашицын ебанулся и зачем-то с какого-то перепоя говорит про утечки, а на самом деле он прочитал мой комментарий до правки, когда я заметил, что говно не в стратегии работы с памяться, а в том, что идёт работа с указателем на неописанную структуру.
          Ответить
          • Надо запретить редактирование комментов, на которые уже ответили. А еще лучше - проверку на модификацию треда в момент отправки.

            "Простите, но в треде появились новые сообщения, или кто-то что-то исправил."
            Ответить
            • Проблема не в этом. От ответил после моего редактирования.
              Проблема в том, что сток показывает только первую версию комментария, которая до редактирования.
              Ответить
              • Ну да, сток обновляется только при отправке нового сообщения. Если бы кто-то в соседнем треде что-то написал - в стоке бы была правильная версия.
                Ответить
              • Да кстати, сток еще и обновляется не мгновенно, видимо по таймеру. Иногда успеваю исправить коммент, и в сток попадает уже новая версия. Иногда нет.
                Ответить
                • А вот бы там отображались только непрочитанные коментарии... *размечтался*
                  Ответить
            • Версии комментариев и никаких проблем.
              Ответить
              • И версии говнопостов.
                И потихоньку Говнокод превращается... превращается Говнокод... в говногитхаб.
                Ответить
                • В говновику.
                  Предыдущая версия комментария содержала ссылки на неавторитетные источники, поэтому была отклонена.
                  Ответить
                  • > В говновику.

                    Звучит как Виктория Копро.
                    Ответить

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