LINUX.ORG.RU

Правильный(???) стиль работы со строковыми данными на С

 ,


2

4

Иногда (прямо сейчас) приходится обрабатыавть строки на C.
Меня коробит от громоздкости операций выделения памяти, конкатенации и самое главное это snprintf с проблемой размера буфера под конечную строку, гигантское поле для выращивания вских мемориликов по невнимательности.

К примеру, размеры mult1_str, mult2_str и equal_str известны, нужно выделить память под всю строку:

snprintf(
    buf,
    buflen,
    "%s miltilple %s equals %s",
    mult1_str,
    mult2_str,
    equal_str
    );
варианты:
- махнуть шашкой и сделать килобайт на стеке ( ((( )
- ничем не размахивать и посчитать руками. (еще хуже)
- написать функцию которая будет вычислять длину «%s miltilple %s equals %s» без символов подстановки (уже лучше)
- отказаться от snprintf и собирать строку пачкой конкатенаций с аллокациями памяти и прочим...

А как делаешь ты?


Судя по множественным ошибкам в ОП, сишка тебе противопоказана. А вообще snprintf тормозит, кто тебя только научил этой гадости. Твои выделения по 5 байт памяти на самом деле быстрее чем они должны быть на самом деле, glibc достаточно умная для этого.

anonymous
()
Ответ на: комментарий от anonymous

ошибки вижу и не парюсь, я был двоечник, меня это оправдывает.
я не о скорости, а о удобстве

ocr
() автор топика

Например:

char *
format_str(const char format[], ...)
{
    va_list ap;
    va_start(ap, format);
    va_list aq;
    va_copy(aq, ap);

    size_t len = vsnprintf(NULL, 0, format, ap);
    va_end(ap);

    char *result_buf = malloc(len + 1);
    if(result_buf != NULL)
    {
        (void)vsprintf(result_buf, format, aq);
    }
    va_end(aq);

    return result_buf;
}

Я предполагаю, что скорость и память не критичны. snprintf() тратит время на разбор строки, ещё и дважды в данном случае, плюс динамическая аллокация.

xaizek ★★★★★
()
Ответ на: комментарий от ocr

Ну так макросом оберни, двоечник. Не обязательно дерьмо генерить, когда можно сделать аккуратно.

anonymous
()

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

Если в проекте есть GLib, то функциями оттуда.

Правильный

Правильного способа нет.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)

man printf

http://man7.org/linux/man-pages/man3/printf.3.html

To allocate a sufficiently large string and print into it (code cor‐ rect for both glibc 2.0 and glibc 2.1):

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

       char *
       make_message(const char *fmt, ...)
       {
           int size = 0;
           char *p = NULL;
           va_list ap;

           /* Determine required size */

           va_start(ap, fmt);
           size = vsnprintf(p, size, fmt, ap);
           va_end(ap);

           if (size < 0)
               return NULL;

           size++;             /* For '\0' */
           p = malloc(size);
           if (p == NULL)
               return NULL;

           va_start(ap, fmt);
           size = vsnprintf(p, size, fmt, ap);
           va_end(ap);

           if (size < 0) {
               free(p);
               return NULL;
           }

           return p;
       }

Домашнее задание: найдите в этом коде:

1. явный баг, влекущий UB при определённых условиях;

2. лишнюю проверку.

shdown
()
Ответ на: комментарий от NeXTSTEP

пример шикарен, не знал, до конца ман не дочитывал

ocr
() автор топика
Ответ на: комментарий от shdown

тоже хорошее решение. согласен, дополнительными длинами символов подстановки можно принебречь

ocr
() автор топика

std::string, std::stringstream

invy ★★★★★
()

считаю самый подходящий вариант это длина форматной строки + известные длины и забить на подстановочные допсмиволы.

std::string, std::stringstream

QString, только QString

ocr
() автор топика

А как делаешь ты?

Не пишу на С если нужно работать со строками, лучше Perl. Ну а если очень надо, нужна библиотека для работы со строками, она тебе все оптимизирует.

Deleted
()

приходится обрабатыавть строки на C.

Сочувствую

А как делаешь ты?

Использую fortran или python -там со строками проще. Ну или хотя бы C++.

grem ★★★★★
()

snprintf
- махнуть шашкой и сделать килобайт на стеке (в дин. памяти)

Если бы ты знал сколько килобайт для служебных целей выделяет (g)libc для работы всяких там *printf, включая буферы для файловых потоков, то ты бы не задумываясь выбрал этот пункт.
Выделить достаточное количество перед началом обработки, освободить в конце.

anonymous
()

читать man не пробовал ?

там вообще-то написано как определить размер результирующей строки

и есть ссылка на asprintf :-)

MKuznetsov ★★★★★
()
Последнее исправление: MKuznetsov (всего исправлений: 1)

Правильный

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

Deleted
()

Все сишники игнорируют всё, что не libc? Берешь GLib или какие-нибудь велосипеды с подобным функционалом, пара строк - и твои волосы мягкие и шелковистые. Нет, буду мозга ипать, память выделять, рукама считать.

meliafaro ★★★★★
()
Ответ на: комментарий от invy

Потенциальная проприетарщина

да лан, позавчера смотрел исходник QNetworkAccessManager, если ты про Qt

ocr
() автор топика
Ответ на: комментарий от Deleted

код на С был прост и быстр пока заказчик не начал требовать фич. Уже после стало понятно что нужно было использовать плюсы. Опыт, мать его...

ocr
() автор топика
Ответ на: комментарий от ocr

Ну будет половинка на С, половинка на С++, а лучше вообще Python к примеру... Ну или Perl, что больше любишь.

Deleted
()
Ответ на: комментарий от Deleted

из того небольшого опыта общения с заказчиками что у меня есть, я сделал вывод что понятие скорости исполнения у всех различается, оно больше носит интуитивный характер когда нет четких метрик.
Сейчас взял за правило оставлять за собой право выбора инструмента исполнения. Исключения составляют те кто может аргументировать свою позицию или предупредить о каких-то подводных камнях. Считаю что проще переплатить $5 за впс с более мощным cpu чем корячиться вот так как я со строками))

ocr
() автор топика

Выделяю мегабайт и snprintf'ом заполняю буфер.

А на мелкоконтроллерах париться не о чем: там нет дебильных printf'ов, и все делается ручками. Аккуратно и навечно.

anonymous
()
Ответ на: комментарий от ocr

Хреновый у тебя опыт, что пришлось с С на говнокресты перейти.

Кошерный сишник никогда не сядет в лужу. И всегда найдет выход из положения, чтобы аккуратно и совершенно нересурсоемко решить задачу.

А какой-нибудь говножабист или пхытонист при этом в 10 раз больше ресурсов потребит, чтобы подобное решить...

anonymous
()
Ответ на: комментарий от Deleted

по сути, хрюникод вообще никому не нужен. Это - излишняя сучность, которую нужно бритвой Оккама по горлу!!11

anonymous
()
Ответ на: комментарий от anonymous

Он больше нужон чем ненужон, но иногда ненужон.

Deleted
()
Ответ на: комментарий от Deleted

Блин, а что, своего мозга нет, чтобы написать парсер для работы со строками? Это ж одной недели дело!!!11

anonymous
()
Ответ на: комментарий от Deleted

А потом ты в абдуринщика превратишься...

anonymous
()
Ответ на: комментарий от Deleted

я вижу нотки принебрежения в

куте ваш

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

ocr
() автор топика
Ответ на: комментарий от ocr

я вижу нотки принебрежения в

Есть такое, но мне просто не нравится подход Qt.

точно так же и относился пока не посмотрел сорцы

Мне сишарф больше понравился, не смотрел в его исходники.

Deleted
()
Ответ на: комментарий от anonymous

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

ocr
() автор топика
Ответ на: комментарий от Deleted

не нравится подход Qt

первое впечатление было такое же.
для того чтобы так не сталось яростно не рекомендую читать макса шлее, новичка пугает количество классов, витиеватость QObject и попытка объять фреймворком все насвете. Считаю что лучший подход к изучению основ Qt это типа интерактивной лекции с профи

ocr
() автор топика
Ответ на: комментарий от ocr

новичка пугает количество классов

Нет, меня пугает то что для банальных вещей нужно делать 100500 действий, а количество классов это прекрасно, если они делают свое дело.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.