The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 05-Янв-14, 22:46  [смотреть все]
Сейчас словил сегфолт при выводе строки длиной 636180 байт.

Сегфолтная команда:

fprintf(stderr, "%s", message);

где message имеет тип "const char *message" и размер данных в  636180 байт.

В стеке вызовов видно, что после функции fprintf() были вызваны:

strlen ()    
__GI__IO_fputs (str=0xb2379018 <Address 0xb2379018 out of bounds>, fp=0xb6ecc960 <_IO_2_1_stderr_>)

- т. е. сначала fputs(), последней strlen().

Сегфолт в дебрях strlen(). (Мне не нравится и строка с fputs(), ибо в ней "Address 0xb2379018 out of bounds").

Таких проблем на коротких строках (чуть более 1000 знаков) не возникает.


Вопрос: существуют какие-то ограничения в компиляторах на работу с сишными строками? Я то думал, что размер строки ограничивается максимальным числом unsigned int. А тут вона как - 630 КБ прожевать не может.

Или, к примеру, существует какое-то ограничение на работу с потоком ошибок, только я о нем не знаю?

Если это важно: gcc (Debian 4.7.1-7) 4.7.1

  • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! skb7, 03:04 , 06-Янв-14 (1)
    >[оверквотинг удален]
    > - т. е. сначала fputs(), последней strlen().
    > Сегфолт в дебрях strlen(). (Мне не нравится и строка с fputs(), ибо
    > в ней "Address 0xb2379018 out of bounds").
    > Таких проблем на коротких строках (чуть более 1000 знаков) не возникает.
    > Вопрос: существуют какие-то ограничения в компиляторах на работу с сишными строками? Я
    > то думал, что размер строки ограничивается максимальным числом unsigned int. А
    > тут вона как - 630 КБ прожевать не может.
    > Или, к примеру, существует какое-то ограничение на работу с потоком ошибок, только
    > я о нем не знаю?
    > Если это важно: gcc (Debian 4.7.1-7) 4.7.1

    У меня на 100 МБ работает:


    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define LEN (100*1024*1024)

    int main(void)
    {
        char *s;
        int ret;

        /* Allocating */
        s = (char *)malloc(LEN * sizeof(char));
        if (s == NULL) {
            perror("unable to allocate string");
            exit(EXIT_FAILURE);
        }

        /* Create content*/
        memset(s, 'x', LEN * sizeof(char));
        s[LEN-1] = '\0';

        /* Printing out */
        ret = fprintf(stderr, "%s", s);
        if (ret < 0)
            fprintf(stderr, "Error in fprintf: %d\n", ret);

        /* Release allocated memory */
        free(s);

        return EXIT_SUCCESS;
    }

    Проверьте у себя этот код, я делал так:


    $ gcc -Wall -pedantic -ansi -O2 -s main.c
    $ ./a.out

    Убедитесь, что вы в своем коде не забыли проверить код возврата при выделении памяти под строку, и не забыли последний символ сделать нулевый (см. zero-terminating string). Не должно быть ворнингов от компилятора при сборке с флагом "-Wall". Также советую проверить свой код с помощью cppcheck:


    $ cppcheck --enable-all main.c

    Если код правильный -- тогда сведите его к минимуму так, чтобы у вас воспроизводилась описанная проблема, и выложите сюда.

    • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 03:09 , 06-Янв-14 (2)

      > У меня на 100 МБ работает:

      Спасибо, уже разобрались на ЛОРе. Дело было не в сишных строках, а в особенностях Qt-ного QByteArray.data(). Этот вызов не гарантирует, что сразу после вызова полученный указатель будет указывать на корректные данные. Хотя в документации написано противоположное.

      http://www.linux.org.ru/forum/development/10015954

      • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! skb7, 04:18 , 06-Янв-14 (3)
        > Дело было не в сишных строках, а в особенностях Qt-ного QByteArray.data().

        Нет, вы не разобрались. Qt там вообще ни при чём. Вы просто не знаете C++.

        > Этот вызов не гарантирует, что сразу после
        > вызова полученный указатель будет указывать на корректные данные. Хотя в документации
        > написано противоположное.

        Конечно же гарантирует и указатель БУДЕТ указывать на корректные данные. Этот вызов просто выдаст вам адрес, по которому УЖЕ находятся данные. И опять же, Qt тут ни при чем.
        Ваша проблема -- в незнании языка, документация Qt тут не поможет, нужно читать документацию на язык.

        Чтобы не быть голословным, объясню, в чем на самом деле ваша проблема.

        Это ваш код:


        const char *message=msg.toLocal8Bit().data();
        unsigned int messageLen=msg.toLocal8Bit().size();
        printf("Len of line: %d\n", messageLen);
        fwrite(message, sizeof(char), messageLen, stderr);

        1. Когда вы делаете msg.toLocal8Bit() в правой части выражения (после равно), создается временный объект типа QByteArray.
        2. После того, как первая строка вашего кода выполнится, этот временный объект автоматически удалится.
        3. Поскольку ваша переменная message указывает на данные удалённого временного объекта QByteArray -- этот адрес, который она содержит -- невалидный (т.е. указывает на участок памяти, где может быть уже что угодно).
        4. При попытке сделать fwrite(message), функция fwrite() пытается разыменовать message, но этот участок памяти уже не принадлежит вашему приложению, он был возвращен операционной системе при удалении временного объекта. Вот тут вы и получаете сегфолт, потому что попробовали залезть в память, которую ОС не выдавала вашему приложению.

        Чтобы избежать этой проблемы, можно написать этот код так


            {
                // Use copy constructor to store temporary variable
                QByteArray tmp(msg.toLocal8Bit());
                const char *message = tmp.data();
                unsigned int messageLen = tmp.size();

                printf("Len of line: %d\n", messageLen);
                fwrite(message, sizeof(char), messageLen, stderr);
            }

        Фигурными скобки ограничивают зону видимости временной переменной tmp. После закрывающейся фигурной скобки tmp будет уничтожена (т.к. она находится на стеке).

        C++ замечательный язык и аналогов ему нет и не будет: он позволяет вам применять самые высокоуровневые абстракции (ООП, шаблоны и т.д.), генерируя при этом наиболее эффективный машинный код. Попытка сделать его проще для безоговорочно человека приведет к огромному увеличению потребления системных ресурсов вашим приложением. Но чтобы писать на нем, надо понимать, как он работает.

        На самом деле я так понимаю вы никогда ничего на C++ не писали до этого? Надо понимать как работает язык. Почитайте Скотта Майерса "Эффективное использование C++. 55 верных советов". А лучше до этого почитайте Брюса Эккеля "Философия C++ (2 тома)".

        • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 17:16 , 06-Янв-14 (4)
          С точки зрения C/C++ то что вы написали - верно. Эта особенность языка очень неудобна, и заставляет программиста писать не с использованием языка, а "на языке". То есть, по логике вещей хотелось бы писать декларативно: взяли то, сохранили там, положили туда. А приходится писать так, что потом сам черт ногу сломит.

          Вот здесь декларативный подход:


          const char *message=msg.toLocal8Bit().data(); // Сообщение как строка
          unsigned int messageLen=msg.toLocal8Bit().size(); // Длина сообщения
          printf("Len of line: %d\n", messageLen);
          fwrite(message, sizeof(char), messageLen, stderr); // Вывод строки в поток

          Вместо него язык диктует какие-то функциональные извращения:


          unsigned int messageLen=msg.toLocal8Bit().size(); // Длина сообщения
          printf("Len of line: %d\n", messageLen);
          fwrite(msg.toLocal8Bit().data(), sizeof(char), messageLen, stderr); // Вывод байт в поток путем получением указателя на данные временно созданного объекта QByteArray

          Это же не код а ублюдство какое-то.

          • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! skb7, 18:51 , 06-Янв-14 (5) +1
            > Эта особенность языка очень неудобна

            Только до тех пор, пока вы не знаете язык, на котором вы пишите.


            > и заставляет программиста писать не с использованием языка, а "на языке"

            Да кто вам таких глупостей наплел, что можно писать "с использованием языка", т.е. не зная язык?! А говорить вы тоже хотите с использованием языка, а не на языке? Хотите программировать, не изучая язык -- рисуйте лучше блок схемы. Я уже насмотрелся на код силиконщиков, которые пишут всё в одной функции, используя только magic numbers, без комментариев, без использования фреймфворков и применяя какие-то абсолютно нелепые стили кодирования. Они тоже думают, что кодируют "с использованием языка". Лучше б такие люди просто блок-схемы рисовали, а нормальные программисты уже нормальный код писали по ним.


            > То есть, по логике вещей хотелось бы писать
            > декларативно: взяли то, сохранили там, положили туда.

            Процессор не работает декларативно, он работает императивно. Чем дальше вы будете отходить от языка машины -- тем больше ресурсов будет потреблять программы, написанные на таком языке. Теперь, задача программиста -- не написать программу максимально удобным и простым для себя образом, а написать программу, которая будет наиболее выгодна и удобна пользователю (в первую очередь). А значит, будет работать максимально эффективно и потреблять минимум системных ресурсов, имея при этом максимальную отзывчивость интерфейса.


            > А приходится писать так, что потом сам черт ногу сломит.

            Извините, но если вам такая простая фича языка доставляет столько сложностей, то мне сложно представить, что вы скажете про мета-программирование (templates), или что вы скажете когда дойдёт дело до серьезной алгоритмики или математики, или до работы с железом, где кроме программирования надо еще понимать как работает железо, ОС, и знать электронику. Там вещи сложнее на несколько порядков, и то что временный объект в RHS выражения автоматически удаляется -- об этом вообще на автомате думаешь, без какого-либо дискомфорта.


            > Вместо него язык диктует какие-то функциональные извращения

            Каждый язык диктует свои правила, на то он и язык. А извращения или нет -- это субьективно. Как по мне, после 3-х лет программирования на C++ и 2-х лет на чистом Си (профессионально), -- автоматически создаваемый и убиваемый временный объект в правой части выражения -- это очень удобно, это несомненно фича, а не бага.

            • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 09:16 , 09-Янв-14 (9)
              > что вы скажете когда дойдёт дело до серьезной алгоритмики или математики, или до работы с железом, где кроме программирования надо еще понимать как работает железо, ОС, и знать электронику. Там вещи сложнее на несколько порядков

              Вот это вот ненадо сказки рассказывать про сложности с железом. Я прогал на Ассемблере под разные процессоры, включая защищенный режим i386, причем инициализировал его вручную. А для простых процессоров половину машинных кодов наизусть знал. На Ассемблере все предельно просто и наглядно, в отличие от C/C++.

          • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! pavlinux, 23:16 , 06-Янв-14 (6)
            > Вместо него язык диктует какие-то функциональные извращения:
            >

            > unsigned int messageLen=msg.toLocal8Bit().size(); // Длина сообщения
            > printf("Len of line: %d\n", messageLen);
            > fwrite(msg.toLocal8Bit().data(), sizeof(char), messageLen, stderr); // Вывод байт в поток  путем получением указателя на данные временно созданного объекта QByteArray
            >

            > Это же не код а ублюдство какое-то.

            Это не плюснутый код, это мутант из С и С++

            Вот Ц++


            #include <iostream>

            std::cerr << msg.toLocal8Bit().data();


            ---

            Мне непонятно другое, - пишут на С++, более того даже на QT, но упорно лезут в С.
            Накой хрен в QT нужны fwrite/fprintf/sizeof/... ?

            • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! skb7, 01:06 , 07-Янв-14 (7)
              > Накой хрен в QT нужны fwrite/fprintf/sizeof/... ?

              В Qt для этого можно использовать qDebug(), qWarning() и прочие. Но если почитать тред на ЛОРе, ссылку на который автор приводил выше, то он там говорит, что он эти функции переопределил. Что помешало использовать плюсовые cout/cerr не знаю -- наверное плохое знание языка помешало :)


              > Мне непонятно другое, - пишут на С++, более того даже на QT,
              > но упорно лезут в С.

              Потому же, почему неправильно работают с временными объектами в правой части выражения -- не знают C++ потому что.


              > std::cerr << msg.toLocal8Bit().data();

              я бы еще "<< std::endl" добавил :)

              • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! pavlinux, 03:44 , 07-Янв-14 (8)
                > Потому же, почему неправильно работают с временными объектами в правой
                > части выражения -- не знают C++ потому что.

                ООП - этож конструктор "Сделай Сам", только свои данные и цифры подставляй, и правильно собери.

              • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 09:24 , 09-Янв-14 (10)
                > В Qt для этого можно использовать qDebug(), qWarning() и прочие. Но если
                > почитать тред на ЛОРе, ссылку на который автор приводил выше, то
                > он там говорит, что он эти функции переопределил. Что помешало использовать
                > плюсовые cout/cerr не знаю -- наверное плохое знание языка помешало :)

                При работе с потоками есть одна проблема. Когда вы пишите

                поток << "Строка" << переменная;

                то автоматически, в выводе после "Строка" будет добавлен пробел. Хотя вы его не пишите, но он добавляется, хотите вы этого или нет. Часто мне нужно писать в поток без пробела. А стандартный оператор << мне этого не позволяет.

                Поэтому я пользуюсь функциями форматного вывода, в них такой проблемы нет.

                • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! pavlinux, 13:15 , 09-Янв-14 (11)
                  > При работе с потоками есть одна проблема. Когда вы пишите поток << "Строка" << переменная;
                  > то автоматически, в выводе после "Строка" будет добавлен пробел. Хотя вы его
                  > не пишите, но он добавляется, хотите вы этого или нет.

                  Да ты чо!!! :)


                  std::cerr.fill('0');
                  std::cerr << msg.toLocal8Bit().data();

                  Если мне мозг не изменяет fill(char s) это заполнитель,
                  или даже символ-заменитель всех не печатных символов.
                  Проще говоря - чтоб консоль не засрать бинарными кодами.


                  > Часто мне нужно писать в поток без пробела. А стандартный оператор <<
                  > мне этого не позволяет. Поэтому я пользуюсь функциями форматного вывода,
                  > в них такой проблемы нет.

                  Уж насколько я ненавижу С++, но блин, в <iostream>  

                  << - это оператор ФОРМАТИРОВАННОГО вывода, там ещё есть не форматированный,
                  а именно .put и .write  


                  std::cerr.write(msg.toLocal8Bit().data());


                  • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 14:22 , 09-Янв-14 (12)
                    >[оверквотинг удален]
                    >> то автоматически, в выводе после "Строка" будет добавлен пробел. Хотя вы его
                    >> не пишите, но он добавляется, хотите вы этого или нет.
                    > Да ты чо!!! :)
                    >
                     
                    > std::cerr.fill('0');
                    > std::cerr << msg.toLocal8Bit().data();
                    >

                    > Если мне мозг не изменяет fill(char s) это заполнитель,
                    > или даже символ-заменитель всех не печатных символов.
                    > Проще говоря - чтоб консоль не засрать бинарными кодами.

                    Теперь вопрос. Тебе нужно написать в формате какого-нибудь лога:

                    std::cerr << "msg" << number << ": Message text";

                    По-умолчанию тебе впечатает:

                    msg 15 : Message text

                    А нужно

                    msg15: Message text


                    Ты весело поставил

                    std::cerr.fill('0');

                    Ну пусть даже поставишь

                    std::cerr.fill('');

                    И что ты получишь?

                    • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! skb7, 17:56 , 09-Янв-14 (13)
                      > По-умолчанию тебе впечатает:
                      > msg 15 : Message text

                      Код:


                      #include <iostream>

                      int main()
                      {
                          int n = 15;
                          std::cerr << "msg" << n << ": Message text" << std::endl;
                          return 0;
                      }


                      Собираю, выполняю:


                      $ g++ -Wall -O2 -s main.cpp
                      $ ./a.out


                      Выводит:


                      msg15: Message text


                      Что я делаю не так?

                      Может это у вас консоль в QtCreator выводит с приколами в свой терминал? Попробуйте запустить в консоли.

                      • C, C++. Какова max длина сишных строк? (сегфолт на ~640 КБ), !*! xintrea, 23:00 , 09-Янв-14 (14)
                        >> По-умолчанию тебе впечатает:
                        >> msg 15 : Message text
                        > Может это у вас консоль в QtCreator выводит с приколами в свой
                        > терминал? Попробуйте запустить в консоли.

                        Да, сейчас проверил - это особенность Qt и qDebug(). Причем qDebug() лепит лишние пробелы и в обычную консоль. Ну а так как про qDebug() написано что class provides an output stream for debugging information, то я грешным делом подумал что так ведет себя любой stream.

                        Зачем сделали лишний пробел по умолчанию - неясно, но его можно походу отключить через метод nospace(). Но если пользоваться qDebug(), то дополнительные пробелы отключаются только на одну строку ибо это конструктор, посему nospace() надо писать каждый раз, или создавать один глобальный объект класса QDebug, и его настраивать один раз и пользовать его.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру