1. C++ / Говнокод #3190

    +144

    1. 1
    2. 2
    3. 3
    4. 4
    string buf;
    ...
    char c_buf[MAX_LEN];
    strncpy(c_buf, buf.c_str(), MAX_LEN);

    в чём ошибка?

    Запостил: skor4ik, 10 Мая 2010

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

    • Для таких вопросов есть stackoverflow.com
      Ответить
      • нет, ошибка не в этом, переполнения стека тут не может быть
        Ответить
        • Вас ввело в заблуждение доменное имя упомянутого мной сайта.
          Ответить
    • В том, что для корректной роботы необходим buf длиной не больше MAX_LEN-1, ибо не влазит символ конца строки? и надо
      char *c_buf = new char[buf.length() + 1];
      strncpy(c_buf, buf.c_str(), buf.length() + 1);

      ?а переполнения действительно не будет
      Ответить
      • нет, не в этом, всё проще и неочевиднее, в данном случае просто строка не заполнится null-байтом, но это не важно
        код strncpy(c_buf, buf.c_str(), MAX_LEN - 1); тоже не верный
        Ответить
        • я и не писал MAX_LEN - 1, я предлагал вычислить длину buf, выделить сколько надо памяти и скопировать все, включая 0x00. и имхо контекста мало. мы же хотим скопировать buf в c_buf и только, да?
          Ответить
          • да, и ваш код тоже неверный =)
            почему? в этом и есть загадка
            Ответить
    • может быть нужно так:

      char c_buf[MAX_LEN + 1];
      strncpy(c_buf, buf.c_str(), MAX_LEN);
      c_buf[MAX_LEN] = 0;
      Ответить
    • показать все, что скрытоПо мне, так проще так:
      cbuf := buf;
      Ответить
      • При любом модифицирующем вызове к buf указатель почти наверное будет указывать на мусор.
        Ответить
    • Еще один угадайщик?
      Нормально там все.
      Ответить
      • strncpy копирует до null-байта, в std::string null-байт не является концом строки и может его содержать не в конце,
        нужно использовать memcpy
        Ответить
        • Да что вы говорите!
          http://www.cplusplus.com/reference/string/string/c_str/
          Ответить
          • я прав, например, ошибка может происходить при чтении из файла содержащего нули (ноль не является концом файла) в std::string

            вот код для примера:
            string s("qwerty");
            s[3]='\0';
            printf("%s\n", s.c_str());
            cout << s << endl;
            cout << "s size:"<<s.size() << endl;

            null-байт не является концом строки, c_str() просто возвращает указатель на начало буфера, гарантируя ноль в конце, а не на си-строку.
            Ответить
        • > string::c_str
          > Generates a null-terminated sequence of characters
          Ответить
          • Вот и я о чем.
            Привет :)
            Ответить
            • Может, конечно, с++ники ещё большие мудаки, чем мы все думаем, и действительно, функция, которая должна возвращать валидную с-строку, не стрипит нули (строка с такими нулями нопремер может кодироваться в wchar'ами, а си-строки подразумевают максимум utf8 и нуль посреди строки там не может быть), я не знаю, всё может быть.
              Ответить
              • тогда смысл обсуждать говнокод на с++ не разбираясь в с++?=)
                Ответить
                • Мне интересно, хочу узнать.
                  Ответить
                • Человек, программирующий в Си и С# (как cfdev) на должном уровне может понимать и С++.

                  зы: Надеюсь не сильно ошибся, сделав предположение относительно самых часто используемых вами языков. :)
                  Ответить
            • Тебе перевести?
              > string::c_str
              > Generates a null-terminated sequence of characters
              Строка заканчивается нулём. Там не написано, что посреди строки не может быть null символа. Если не написано, то он может, взависимости от того, что поместили в std::string.
              Ответить
              • Тогда у этой функции нет смысла.

                По уму надо кодировать в utf8. А нахрена у utf8 нули посередине, я не знаю.
                Ответить
                • Алсо, в Си тоже никто не мешает вставить ВНЕЗАПНЫЙ нуль посередине строки.

                  Только вот говнокодом будет не использование strncpy, а вставка этого нуля.
                  Ответить
    • Нормально оно работает. Без контекста не говнокод, как мне кажется. А раз не говнокод и тут не викторина "придумай ситуацию с вероятность ->0 при которой код будет бажить", то не смешно вовсе.
      Ответить
    • buf.c_str() может быть в конце последней прокомитченной страницы, и если он меньше MAX_LEN, то 0x...5 гарантирован (win) - это пожалуй лучшее, что ждёт автора этого кода, если наступит сразу, а так ловить это можно очень долго.... :)
      Ответить
    • А нафига вообще копировать в С-строку из string ? Если есть метод c_str(), то почему бы его и не использовать там, где потребуется представление нуль-терминированной строки.

      Но если дело тупо в этих трех строчках, то надо так:
      string buf;
      ...
      char c_buf[MAX_LEN];
      strncpy(c_buf, buf.c_str(), MAX_LEN-1);
      c_buf[MAX_LEN-1]='\0';

      Самое страшное, что тут может случиться это усечение строки. Но для того strncpy() и придумана.
      Если говорить о теме наличия нулей в string'е, то сам дурак, если зная это копируешь в С-строку.
      Ответить
      • >А нафига вообще копировать в С-строку из string
        не в С-строку, а в неконстантный буффер, а буфферы используются постоянно =)

        >Самое страшное, что тут может случиться это усечение строки. Но для того strncpy() и придумана.
        верно, оно и случается, суть в том, что для копирования буффера из std::string в буффер си нужно использовать memcpy вместо strncpy, но большинство новичков не задумываясь используют strncpy, так как думают, что string содержит null-байт только на конце.
        Ответить
        • Так ведь Онотеле же не читает говнокод, а остальным благородным донам логика, наверняка, доподсказывает, что раз вы используете метод для работы с с-строками (с_str) и функцию для работы с с-строками (strncpy), то хотите иметь в c_buf с-строку со всеми вытекающими, а не просто массив значений. Стало быть постановка вопроса не очень корректна, т.к. приведенный кусочек вполне себе работоспособен вне контекста. А это изоблечает "новичка" в вас, т.к. при проектировании своей программы вы не задумались, что у вас не строка, т.е. неправильно был выбран тип данных.
          Ответить
          • то есть вы согласны, что это говнокод?
            уже хорошо, а чем плохо использовать std::string для хранения буфера?
            Ответить
            • Это стало говнокодом, когда стало известно для чего здесь используется std::string. Для буфера абстрактных данных - вектора, списки ...
              Ответить
              • +100500
                Ответить
              • Если std::string допускает использование для бинарных данных, то почему нет?
                Говнокод там, где использовали strncpy - строковые функции, не предназначенные для бинарных данных.
                Ответить
                • >Если std::string допускает использование для бинарных данных, то почему нет?
                  Чтобы не вводить в заблуждение читающего код хотя бы. А если будете использовать другой тип символа в std::basic_string, то надо еще char_traits для него определить. А оно вам надо?
                  Про шурупы забитые молотками я думаю говорить не стоит.
                  Ответить
                  • с таким подходом обычно и получается говнокод!

                    >Чтобы не вводить в заблуждение читающего код хотя бы.
                    достаточно написать комментарий, что здесь стринг используется для хранения буффера (под буффером я тут понимаю массив байтов)
                    Ответить
                    • а чем std::vector не массив байтов? и удобнее чем со стрингом получится...
                      Ответить
        • Для копирования строки в С++ следует использовать strcpy, так как строка в С++ - это массив символов, заканчивающийся нулевым символом, и по определению содержать других нулевых символов он не может.

          Для копирования области памяти в С++ следует использовать memcpy и не задумываться о каких-то там нулях, так как размер буфера памяти хранится где-то сугубо отдельно.

          Для копирования строк в формате BSTR следует пользоваться специальными функциями, так как данные строки не являются совместимыми со строками С++.

          Читать из буфера произвольные даннные в бинарном формате в строку, а потом использовать ее как строку С++, если она заведомо содержит не строковые данные, может только тупорылый мудак, который вообще ничего не понимает в программировании. Читать бинарные данные в std::string может только двоичный мудак с фимозгом рака.
          Ответить
          • Как же все запущенно в этом вашем С++. Еще парочка подтверждений факта, что плюсисты - обыкновенные зубрилки. Столько мозготраха из-за такой мелочи.
            Ответить
            • Ни слова про этот ваш С++, я раковый расовый шарпист!
              Ответить
              • Сменял шило на мыло?
                Ответить
                • Избавился от самого любимого велосипеда - написание собственной реализации строки, с преферансом и куртизанками.
                  Ответить
                  • В С++ нет необходимости написания своих велосипедов со шлюхами и блекджеками, если пользовться стандартными без шлюх. Хотя бытует мнение, что шлюхи там всёже есть.

                    зы: Нелюблю писать С++, тк очень длительно. Неужели нельзя было назвать С+. Когда Страус упал и умер, то плюс раздвоился?
                    Ответить
            • Во время программирования С++систы задумываются над внутренней реализацией.

              Зачем программисты задумываются над ней?
              Потому-что ищут наиболее оптимальный путь реализации. При этом не брезгуют выбором наиболее оптимального алгоритма. В функциональных языках алгоритм - единственное, на что влияет программист.
              В свете этого программа на С++ по скорости может выиграть у программы, написанной на ФЯП.

              Не могу спорить, что ФЯП программы легче распараллеливаются автоматически, но с ручной качественным распараллеливанием С++ная программа выиграет у ФЯПнутой программы.

              Не могу спорить, что ФЯП программы легче писать, не задумываясь о мелочах реализации, а значит быстрее.
              Ответить
              • >>В функциональных языках алгоритм - единственное, на что влияет программист.

                Это практически единственное (плюс структуры данных), что имеет значение при разработке.

                >>с ручной качественным распараллеливанием С++ная программа выиграет у ФЯПнутой программы.

                Действительно, зачем Ericsson Эрланг? Надо все на асме переписать. Прямо сейчас. Через 50 лет встретимся.
                Ответить
                • Эрланг пока не предназначен для быстрых расчётов. Например не умеет SSE MMX 3DNow!. Что-бы он быстро что-то делал - ему нужен мега многоядерник или кластер. А это дорого для обывателя.
                  А вот с ручным распараллельванием и всякими SSE MMX 3DNow! можно получить приличную скорость и на пользовательской машине.
                  Да и программиста проще найти. Вы на ФЯП пишете для заказчиков или таких заказчиков нет?
                  Ответить
                  • Когда завезут обывательские 256ядерники (Windows 7 поддерживает) и ФЯП будут поддерживать современные потоковые комманды процессора, то дружно переходим на ФЯП.
                    Ответить
                    • Кстати, эрланг - помоему там интерпретатор используется, хотя может есть и компиляющие версии.
                      Ответить
                  • Такое чувство, что у вас лишь зачаточные знания об этом замечательном языке. Просто его ниша - телекоммуникации, а уж там он любого на лопатки положит, тем более в этой области важнее соблюсти бизнес-логику, а не получить выигрыш в жалкие проценты по производительности (кстати, даже в этом случае на си(++) придется пользоваться заимствованными из функциональной парадигмы вещами).
                    зы На F# пишу прямо сейчас.
                    Ответить
                    • >Такое чувство, что у вас лишь зачаточные знания об этом замечательном языке.
                      Да и о ФЯП в целом, но хочу их увеличить, да и пишу в на императивных языках (пока), в частности приемущественно на С++.

                      1)Если не такой секрет, то расскажите о каких-нибудь ваших проектах и на каком ФЯП писали? Очень интересна их область использования.

                      2)В F# пишите ли вы программы с графическим пользовательским интерфейсом(GUI) и удобно ли это?

                      3)F# позволяет экспортировать функции, что-бы пользоваться ими из неманаджет кода, например на С++?
                      Ответить
        • Полностью согласен с funny_rabbit. Ни слова не сказало о постановке задачи, приведены функции для работы со строками. Как результат - на этом обсуждение и строится. Ясновидящих тут нет.
          Ответить
    • За выделение на стеке MAX_LEN уже стоит оторвать руку, а памяти стоит выделять на 1 байтик больше для всех функций str...
      Ответить
      • А за MAX_LEN-1 ? :))) Вспомнился анекдот про N самолетов как-то сразу :)))
        Ответить
        • Это тот, где оба реактивные?
          Ответить
          • Это когда препод диктует задачу:
            - Летит N самолетов ... нет, N мало, возьмём M.
            Ответить
            • А, я примерно такой же имел в виду:
              - Летит N самолетов ... нет, N мало, возьмём M, и оба реактивные.
              Ответить
    • Каждый С++ говнокод превращается в опусканиеобсуждение С++ VS ZOGФЯП.
      Ответить
      • А казалось бы языки не сравнимы - разных классов и весовых категорий.
        Ответить
    • у меня возник вопрос: как засунуть в std::string данные в которых 0 не будет последним символом, читая их из файла или еще откуда нибудь? че-то я даже не могу догадаться как это сделать (кроме конечно правки текста на лету типа str[10] = 0; )
      Ответить
      • читая из файла, из сокета, вообще из чего угодно, вот пример:
        ifstream fin("file.txt", ios_base::in);
        stringstream stream_buf;
        stream_buf << fin.rdbuf();
        string buf = stream_buf.str();

        теперь buf содержит бинарное содержимое файла
        Ответить

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