LINUX.ORG.RU

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

 


13

7

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

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

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

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

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

★★★★★

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

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

у меня вместо calloc какая-то хрень мутная, наверное аналог malloc, но не проверял. А в конце calloc есть memset, причём на весь размер выделенной памяти.

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

post-factum'у это объясни. Он чего-то возмущается. Хотя в коде явно стоит выбор типа выделения памяти (в зависимости от состояния + размера запроса) и затем если выделено много, то полностью на него делается memset, а если немного, то какую-то непонятную хрень творят, явно превышая размер выделенной памяти (видимо, т.к. все равно память блоками выделяется).

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

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

то нужно оторвать руки этому рукожопому быдлокодеру! Нефиг лишнюю память выделять. Максимум — лишний килобайтик.

1. возрастает фрагментарность памяти, если выделять разные куски. Быстрее выделять одинаковые.

2. лишняя работа memset.

А не гигабайты, как какой-нибудь говнохромой выделяет. Хромоногая скотина — вообще эталон быдлорукожопокода.

что ты ко мне с говнохромом пристал? Я его тоже не использую, ибо, как я уже писал, течёт. ФФ не течёт, а хром течёт. И вообще уродский он какой-то, ваш хромой.

И да, я код хромого не видел, и видеть не желаю.

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

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

post-factum ★★★★★
()
Ответ на: комментарий от Eddy_Em

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

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

а нахрена memcpy, когда можно strcat?

это нафиг на 3 такта быстрее.

В этом меня убедили, но я всё равно буду писать strcat, ибо читаемо.

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

ē-моē! calloc имеет смысл делать, если ты выделяешь какую-нибудь структуру и хочешь чтобы там поля приняли дефолтные нулевые значения (в т.ч. всякие указатели были NULL, чтобы при обращении к ним не вышла жопа). А тупо под строку calloc'ом память выделять... Ну, если тебе влом дописать последний нуль в динамическую строку, еще ладно. Но у тебя же по сути статическая строка! Заполнил, дописал один-единственный нулик и готово!

Эддички, да сколько вас там?! Кто мне только-что объяснял, что надо постоянно делать calloc?

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

я думал, это лично ко мне обращено, собственно, мне и стало интересно, где у меня ошибка в коде, который я пару часов вылизывал и точно знаю, что, где и зачем

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

у меня в glibc так:

void *
__libc_calloc (size_t n, size_t elem_size)
{
  mstate av;
  mchunkptr oldtop, p;
  INTERNAL_SIZE_T bytes, sz, csz, oldtopsize;
  void *mem;
  unsigned long clearsize;
  unsigned long nclears;
  INTERNAL_SIZE_T *d;

  /* size_t is unsigned so the behavior on overflow is defined.  */
  bytes = n * elem_size;
#define HALF_INTERNAL_SIZE_T \
  (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
  if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0))
    {
      if (elem_size != 0 && bytes / elem_size != n)
        {
          __set_errno (ENOMEM);
          return 0;
        }
    }

  void *(*hook) (size_t, const void *) =
    atomic_forced_read (__malloc_hook);
  if (__builtin_expect (hook != NULL, 0))
    {
      sz = bytes;
      mem = (*hook)(sz, RETURN_ADDRESS (0));
      if (mem == 0)
        return 0;

      return memset (mem, 0, sz);
    }

  sz = bytes;

  arena_get (av, sz);
  if (!av)
    return 0;

  /* Check if we hand out the top chunk, in which case there may be no
     need to clear. */
#if MORECORE_CLEARS
  oldtop = top (av);
  oldtopsize = chunksize (top (av));
# if MORECORE_CLEARS < 2
  /* Only newly allocated memory is guaranteed to be cleared.  */
  if (av == &main_arena &&
      oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *) oldtop)
    oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *) oldtop);
# endif
  if (av != &main_arena)
    {
      heap_info *heap = heap_for_ptr (oldtop);
      if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
        oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
    }
#endif
  mem = _int_malloc (av, sz);


  assert (!mem || chunk_is_mmapped (mem2chunk (mem)) ||
          av == arena_for_chunk (mem2chunk (mem)));

  if (mem == 0)
    {
      LIBC_PROBE (memory_calloc_retry, 1, sz);
      av = arena_get_retry (av, sz);
      if (__builtin_expect (av != NULL, 1))
        {
          mem = _int_malloc (av, sz);
          (void) mutex_unlock (&av->mutex);
        }
      if (mem == 0)
        return 0;
    }
  else
    (void) mutex_unlock (&av->mutex);
  p = mem2chunk (mem);

  /* Two optional cases in which clearing not necessary */
  if (chunk_is_mmapped (p))
    {
      if (__builtin_expect (perturb_byte, 0))
        return memset (mem, 0, sz);

      return mem;
    }

  csz = chunksize (p);

#if MORECORE_CLEARS
  if (perturb_byte == 0 && (p == oldtop && csz > oldtopsize))
    {
      /* clear only the bytes from non-freshly-sbrked memory */
      csz = oldtopsize;
    }
#endif

  /* Unroll clear of <= 36 bytes (72 if 8byte sizes).  We know that
     contents have an odd number of INTERNAL_SIZE_T-sized words;
     minimally 3.  */
  d = (INTERNAL_SIZE_T *) mem;
  clearsize = csz - SIZE_SZ;
  nclears = clearsize / sizeof (INTERNAL_SIZE_T);
  assert (nclears >= 3);

  if (nclears > 9)
    return memset (d, 0, clearsize);

  else
    {
      *(d + 0) = 0;
      *(d + 1) = 0;
      *(d + 2) = 0;
      if (nclears > 4)
        {
          *(d + 3) = 0;
          *(d + 4) = 0;
          if (nclears > 6)
            {
              *(d + 5) = 0;
              *(d + 6) = 0;
              if (nclears > 8)
                {
                  *(d + 7) = 0;
                  *(d + 8) = 0;
                }
            }
        }
    }

  return mem;
}

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

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

А в случае, если ты выделенную память сразу же чем-то заполняешь, зачем ее предварительно обнулять?

Это ж как memset раза три прогнать,"на всякий случай"

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

Попробуй часик mjpeg'овое потоковое видео покрутить

не знаю, не пробовал.

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

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

с этим соглаен.

А в случае, если ты выделенную память сразу же чем-то заполняешь, зачем ее предварительно обнулять?

не нужно.

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

Неплохо. Кстати, а почему у тебя в _Generic используются указатели на указатель? Если в лоб делать, то массивы попадают под char*, а не в default? Вроде как не должны...

anonymous
()

Ну как тебе язык, где простейшая операция порождает столь бурную «дискуссию»?

string s1;
string s2;
getline(cin, s1);
getline(cin, s2);

cout << s1 + s2 << endl;

Это C++. Производительность будет примерно та же, что на си. В любой момент ты сможешь переписать узкие места как можно более производительно. Си знать полезно(C++ программист должен его знать), но я бы кресты советовал вместо си использовать.

А для «обычных» задач - вообщ какой-нибудь питон.

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

Будет плохо работать при склеивании строк из статических/локальных буферов, размер которых больше фактически лежащей там строки. Вернее вообще не будет работать, если их явно к указателям не приводить во время использования макроса.

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

Я считаю, что есть всего одна причина использовать плюсы - на них написано билионы разнообразных библиотек. Благо на си (или на плюсах с сишным апи) написано не меньше.

Советовать плюсы в качестве «усовершенствованного си» это просто глумление. Есть куда более приятные аналоги - rust и d.

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

Современные С++ и Современные С это братья. их общий предок Сcirca1979. более того братья находятся в постоянной конвергенции.

таково мнение 2го чела в С-комьюнити Бьярне-Того-Самого.

Плюсы это не усовершенствованые си .

Плюсы это современные Си.

как Си был реакцией на PL/I которым сам во много стал(тока не сразу) а через 2-3 декады лет - когда его стандарт имеет очень много особых случаев.

так и С++ это Algol68 тока в своих скобках и сделанный в одно лица, а не комитетом. ща комитет повелевает :(

приятные аналоги приятны. D уже не воскреснет.

Rust - посмотрим . скока он уже на слуху?

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

C++ со всеми изысками ужасен

С++ ограниченный ограничениями программиста-пользователя или ещё каким кодекондуктом вполне приемлем.

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

Если в лоб делать, то массивы попадают под char*, а не в default?

Да.

Вроде как не должны...

В сети есть примеры, судя по которым да, не должны. Но попадают :) Дополнительный уровень косвенности через указатели решает проблему.

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

Не очень понимаю о чем спорить - есть способ movsb там точно нет переходов и возможной очистки конвейера. Там точно нет больше одной синхронизации с кешем других ядер, потому как она выполняется целиком и разумно сделать синхронизацию после её окончания, если вообще есть эта синхронизация. В побайтовом копировании точно есть циклы и точно надо синхронизировать после каждой записи, не говоря уже что вообще этот кусок кода может быть вытеснен и вообще там время будет непредсказуемо. К этому коду можно придраться в заточенности на конкретный процессор, но никак не в скорости. (тут кстати есть потенциал для межпроцессорного срача :)) В твоём сишном коде в начале нужно поставить #ifdef PURE_C а в конце #endif,а где-то рядом мою в #ifdef_i386 #enfif, и все встанет на места. А с лишней строковой инструкцией все просто - надо строки использовать не с нулем в конце, а с длиной в начале. Тогда останется только movs, а сканирование нафик не нужно. C++ и самопальный класс для строчек, и сделать вид что это и есть С.

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

Будет плохо работать при склеивании строк из статических/локальных буферов, размер которых больше фактически лежащей там строки. Вернее вообще не будет работать, если их явно к указателям не приводить во время использования макроса.

Да, я думал об этом. Но тут при использовании человек должен думать. С другой стороны, можно было использовать strcpy, но memcpy должен быть оптимальнее.

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

аноним подразумевал, что не все старые Си допускали выделение массива(на стеке) чей размер получался через аргументы.

т.е

        int reszblA(int B){
                int m[B];
                //что то делаем m[B]
                return что-то как функция от 
        }

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

что бы обработать в рантайме вызов например reszblA(0)

ну или reszblA(-1)

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

это STL. Которого ты никогда не будешь понимать, т.к. не знаешь C и C++.

А как ты это определил, кстати? У него вроде обычный код.

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

Я считаю, что есть всего одна причина использовать плюсы

А почему ты так считаешь? Насколько я понимаю, у тебя пока нет ни опыта, ни знаний. C++ хороший и практичный инструмент. Я Си знаю хорошо, но на практике предпочитаю C++. Он не уступает си, иногда даже превосходит по скорости, в том смысле, что код на шаблонах неплохо так оптимизируется обычно, и в Си приходится устраивать ад из макросов, чтоб догнать кресты. Я не хейтер макросов(см. мой код копирования строк), если что. Иногда я пишу и на Си.

Советовать плюсы в качестве «усовершенствованного си» это просто глумление.

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

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

Есть куда более приятные аналоги - rust и d.

rust интересен, да. Но он даже не зарелизен еще. D, видимо, мертворожденный, за столько лет до сих пор ничего из себя толкового не представляет. И да, в плане сложности он C++ не уступает=)

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

да, с некоторых пор — часть.

С первого стандарта, если память мне не изменяет.

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

16 лет как минимум - нифиговое такое с некоторых пор.

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

rep movsb до haswell была очень тормозной, только ленивый не писал свою реализацию memcpy на sse и avx

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

sizeof

Тю, и чем это лучше «статической» конкатенации при компиляции?

char combined[] = "string1""string2";

В смысле тут вообще конкатенация ни к чему..

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

А почему ты так считаешь?

Чрезмерно сложный, на мой вкус. Боюсь не потяну. Надо же еще оставить место для раста, когда первая версия выйдет. А от си никуда не деться, как ни крути)

makoven ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Glib Strings

https://developer.gnome.org/glib/stable/glib-Strings.html

Удваиваю. В XXI веке за использование char array в качестве string пора бить канделябром. Использование класса String из какой-нибудь подходящей библиотеки (читай: Glib) есть правильное решение. Там и методы конкатенации, поиска подстроки, вычленения, и прочая поддержка UNICODE.

Camel ★★★★★
()
Ответ на: Бва-ха-ха от Camel

А чем C++ хуже? Одно только RAII уже бы заставило меня использовать C++. Я уже не говорю о перегрузке функций, пространствах имён, шаблонах, ичключениях, минимальном ООП, стандартной библиотеки и пр. и пр.

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

Не хуже

А чем C++ хуже?

В самом деле, чем же C++ хуже? Вы хотите меня об этом спросить? Я где-то сказал что C++ хуже? Отнюдь. Я только высмеял отношение к C как к более плохому языку нежели C++. В то время как он просто другой, не лучше и не хуже. И решать призван другие задачи.

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