LINUX.ORG.RU

Шок от С. Как склеивать строки?

 


13

7

Осваиваю си. Всё шло хорошо пока внезапно не понадобилось склеить строки (константные и переменные). Покурил stackoverflow. Предлагают 2 варианта:

Первый - создать char buf[молись_чтобы_хватило] и делать str(n)cat/sprintf в этот buf.

Второй - использовать asprintf, который расширение, нестандарт и вообще.

Вопрос: как вы склеиваете строки? Может есть какая-нибудь общепринятая либа?

Простите за нубский вопрос

★★★★★

Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от Dron

Всё бы хорошо, только в C строк попросту нет.

string.h и функции из него давно в стандарте C. Посмотри сам.

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

Я имел в виду отсутствие типа

специального типа действительно нет. Не нужен.

А если ты любитель делать типы, то тебе прямая дорога в C++, там уже есть стандартные std::string, QString, но ты можешь сделать свой с блекджеком и шлюхамиCoW и регулярками.

emulek
()

Вот почему сначала надо учить С, а затем высокоуровневые языки. Как ты думаешь, что на самом деле происходит, когда ты пишешь «str1 + str2»?

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

Раз пошла такая пьянка, то вот вам и моя вариация на туже тему:

char *
cat(char *a, char *b)
{
        size_t lena = strlen(a);
        size_t lenb = strlen(b);
        char *c = malloc(lena + lenb + 1);

        if (c) {
                memcpy(c, a, lena);
                memcpy(c + lena, b, lenb + 1);
        }

        return c;
}
beastie ★★★★★
()

Вот это тема...
Сколько нужно программистов, чтобы написать конкатенацию двух строк на Си?...

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

У memcpy есть недостаток. Она неправильно отработает если области, которые ты ей подсунул, перекрываются между собой.

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

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

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

Не, ну 4 страницы.... чтобы разобраться, как склеить строки на Си - это перебор :) (при том что языку уже 4й десяток лет).

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

Выше где-то объяснили, что это нормально для языка, который дает такую гибкость. Сколько людей, столько и мнений.

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

а зачем memcpy, если можно strcpy и strcat? Я очень сомневаюсь, что твой вариант будет быстрее моего, проверь, если тебе не лениво.

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

Выше где-то объяснили, что это нормально для языка, который дает такую гибкость.

Глупости. Плюсы дают большую гибность, а способ там в принципе один.

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

Если не вникать в реализацию? С++ просто скрывает реализацию под слоем абстракций. Не скажу, что это плохо, просто надо понимать, что абстракции всегда текут. В С++ ты не сделаешь str = «a» + «b»; Ага, ввели абстракцию в виде класса string но под ней просвечивает char.

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

а зачем memcpy, если можно strcpy и strcat?

Во-первых, strcat делает внутри себя лишний strlen, а во-вторых, strcpy, как правило, тупа, как пробка, когда как memcpy через SSEx/AVX.

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

абстракции всегда текут

Куда они текут?

но под ней просвечивает char.

Речь как раз о том, что в плюсах взяли и сделали удобные для использования «абстракции», и что самое главное - стандартизировали.

Меня удивляет то, что за 40 лет для Си нет какой-то относительно стандартной библиотеки для стандартных вещей. Есть рантайм, но он подразумевает написание одних и тех же велосипедов постоянно. (эта тема тому подтверждение). Есть glib, но он нестандартен. Удивительно просто.

Ведь когда пишут программы, всё повторяющееся выносят в удобные повторноиспользоуемые функции или классы и библиотеки. А тут за 40 лет воз и ныне там.

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от record

нормальные сишники используют специально обученную strcat(3) из _стандартной_ библиотеки.

В нормальных языках используй '+'

вот именно. А в сишке флейм уже на 5 страниц. Потому-что каждый предложенный способ по своему хорош. А ваш + не оптимален в 95% случаев. Ну вот смотри: имеем 7 девушек, каждая любит свой цвет радуги. Предложение: давайте смешаем все 7 цветов поровну, и оденем всех в белое! Конец немного предсказуем.

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

В данном случае имхо без разницы, т.к. копируется в свежевыделенный участок памяти.

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

Лень тестить, но теоретически должно быть чуть-чуть быстрее, т.к. экономим на повторном поиске конца строки.

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

strcat делает внутри себя лишний strlen

strcpy, как правило, тупа, как пробка, когда как memcpy через SSEx/AVX.

во первых, виденные мною реализации str* не так уж и «тупы», как ты думаешь.

Во вторых, вопрос был про _строки_, а строки не слишком и длинны. Потому «тупая» реализация работает на порядок быстрее.

В третьих, какой и откуда ты получишь профит от SSE, если тебе надо тупо скопировать сотню байт? Скорость по любому упрётся в память/кеш, и простой алгоритм опять даст профит, т.к. проще предсказать→ меньше промахов.

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

что за 40 лет для Си нет какой-то относительно стандартной библиотеки для стандартных вещей.

учи матчасть, есть glibc. И кстати она POSIX.

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

Дело в том, что тупая конкатенация строк — задача довольно таки редкая в C. Для всего остального есть целый набор всякого разного в <string.h> начиная от mem*, через str* и до snprintf.

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

У всего есть причины. 40 лет - нормальный срок для эволюции языков. Для работ со строками есть другие более совершенные (для этой задачи) языки. Qt вот тоже не входит в стандарт С++ и тем не менее, там есть свои строки, которые используются вместо стандартных. Более того, ты можешь написать свой класс строк. Получается этот стандарт, он как бы и не очень нужен. Более, того, думаю, что если посчитать проги написанные с использованием стандартных строк и каких-то других строк, то другие строки скорее всего победят. Студенческие лабы не в счет.

Причины есть у всего. Если стандарта нет, значит он не нужен. Эволюционно не нужен.

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

т.к. экономим на повторном поиске конца строки.

ты учти, что сейчас слово занимает 8 байт, и ищет оно сразу по слову (гуглить shift-or). Ну и строки не так уж длинны, и влезают если не в пару регистров, то в линейку L1.

т.е. вангую примерно равную скорость. ±погрешность измерения.

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

Обычно в зависимости от размера данных используются разные алгоритмы копирования. Но основной мой поинт ведь совсем же не в этом, здесь лишь к слову пришлось. Главная проблема твоего решения в том, что зная длину первой строки, ты упорно вызываешь strcat, выполняя абсолютно бессмысленную, а главное бесполезную работу. Это выдаёт в тебе такого же непрограммиста, как и Эдика. Надеюсь, ты не начнёшь сейчас кукарекать про «что плохого в лишнем strlen»?

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

Дело в том, что тупая конкатенация строк — задача довольно таки редкая в C.

Настолько редкая, что чуть-ли не каждый отписавшийся тут предложил свой велосипед. И мне это тоже приходилось на Си делать. ;)

Для всего остального есть целый набор всякого разного в <string.h> начиная от mem*, через str* и до snprintf.

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

Для меня загадка, почему для плюсов есть весьма навороченный stl, а помимо него ещё есть просто overkill в виде boost'a и Qt, а для C толком ничего и нет.

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

Для работ со строками есть другие более совершенные (для этой задачи) языки.

Это как сферический конь в вакууме. Строки нужны везде и соответственно удобные инструменты для работы с ними.

Qt вот тоже не входит в стандарт С++ и тем не менее, там есть свои строки, которые используются вместо стандартных

Ну и прекрасно же. Qt, MFC, wxWidgets, stl, boost, ... Но везде есть удобные инструменты для работы со строками (и не только).

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

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 2)
Ответ на: комментарий от emulek

Пока динозавры и прочие рыбы трахают мозг девушкам malloc'ами, млекопитающие уже сложили и делают семи девушкам по семь детишечек.

record ★★★★★
()
Последнее исправление: record (всего исправлений: 2)
Ответ на: комментарий от invy

Строки нужны везде

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

и соответственно удобные инструменты для работы с ними.

printf достаточно удобный инструмент для логов.

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

C - небольшой язык, всё что не входит в стандарт надо или писать самому или использовать библиотеки.

Самый идиотизм, что все эти свои выводы ты делаешь даже не открыв n1570 page 382, для ОПа: 7.24.3.2 The strncat function.

ihanick
()

Категория: платиновые треды ЛОРа. Простой вопрос как склеить строки, и 5 страниц срача с говнокодом и срыванием покровов. Аплодирую ТСу.

По теме:

Использую g_strconcat().

Если проект не использует glib, то просто копирую в проект эту функцию из сорцов glib.

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

1) задачу решает? Решает. Отвали.
2) если нужно будет оптимизировать, то будет и оптимизация в виде memcpy/memmove (смотря что больше нравится, мне лично больше нравится memmove).
3) непрограммисту вообще насрать на п.2), пока эти тормоза незаметны; ему важен п.1). Как наткнется, так и п.2) сделает. Но сначала перенесет вычисления на куду =D

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от emulek

нет ты. тс, скорее всего, не имеет особых причин использовать именно c, а не c++

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

Простой вопрос как склеить строки, и 5 страниц срача с говнокодом и срыванием покровов.

А мы тут рядом числа в квадрат возводим. И оцениваем, какие варианты возведения годятся для продакшна, а какие нет.

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

Так он прикручивает свои поделия на каких-то левых микроконтроллерах к телескопам. Разобьёт там телескоп, его и выкинут

niemand
()

Oh shi. Вы на 5 страницах обсуждаете конкатенацию.

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

начётничество mode on:

хм: https://git.gnome.org/browse/glib/tree/glib/gstrfuncs.c:556,592

содержит:

 
gchar*
g_strconcat (const gchar *string1, ...)
{
  gsize   l;
  va_list args;
  gchar   *s;
  gchar   *concat;
  gchar   *ptr;

  if (!string1)
    return NULL;

  l = 1 + strlen (string1);
  va_start (args, string1);
  s = va_arg (args, gchar*);
  while (s)
    {
      l += strlen (s);
      s = va_arg (args, gchar*);
    }
  va_end (args);

  concat = g_new (gchar, l);
  ptr = concat;

  ptr = g_stpcpy (ptr, string1);
  va_start (args, string1);
  s = va_arg (args, gchar*);
  while (s)
    {
      ptr = g_stpcpy (ptr, s);
      s = va_arg (args, gchar*);
    }
  va_end (args);

  return concat;
}

хм не явный extern по нужде : gchar,gsize,g_new,g_stpcpy

https://developer.gnome.org/glib/stable/glib-Basic-Types.html#gchar

typedef char   gchar;

http://developer.gimp.org/api/2.0/glib/glib-Basic-Types.html#gsize

typedef unsigned int gsize;

https://git.gnome.org/browse/glib/tree/glib/gmem.h

#define g_new(struct_type, n_structs)			_G_NEW (struct_type, n_structs, malloc)
хм сколько верёвочки не виться конца и края нет...

и снова https://git.gnome.org/browse/glib/tree/glib/gstrfuncs.c:463,483

gchar *
g_stpcpy (gchar       *dest,
          const gchar *src)
{
#ifdef HAVE_STPCPY
  g_return_val_if_fail (dest != NULL, NULL);
  g_return_val_if_fail (src != NULL, NULL);
  return stpcpy (dest, src);
#else
  gchar *d = dest;
  const gchar *s = src;

  g_return_val_if_fail (dest != NULL, NULL);
  g_return_val_if_fail (src != NULL, NULL);
  do
    *d++ = *s;
  while (*s++ != '\0');

  return d - 1;
#endif
}
хм неявный extern по нужде : HAVE_STPCPY , g_return_val_if_fail

так как ты говоришь поступаешь когда

Если проект не использует glib, то просто копирую в проект эту функцию из сорцов glib.

?

как(чем) тащишь зависимости?

qulinxao ★★☆
()

способ номер раз - считаешь длину объединённой строки, выделяешь буфер, делаешь strncpy, profit.

Способ для ленивых - открываешь стрим в память, пишешь туда пока памяти хватит.

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

Ты скорей разобьешься!

Системой управления я пока не занимаюсь. А занимался бы, естественно, все блокировки и тесты делал бы! Это все-таки не регистрация температур или еще какой второстепенной хрени.

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