LINUX.ORG.RU

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

 


13

7

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

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

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

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

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

★★★★★

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

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

В js замыкания полезны когда создаешь, например, обработчик onclick и этот обработчик утаскивает за собой переменные, что объявлены снаружи него, сохраняя их значения на будущее. Еще можно с их помошью городить модули. Хоть и не обязаьтельно - есть же prototype.

А в сишке зачем замыкания?

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

Да, запилили в C++11, оно работает, только никто не знает — зачем.

Известно, зачем. Чтобы пополнить еще одним пунктом «не использовать ни при каких обстоятельствах» всякие coding guidelines компаний по всему миру.

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

для сопрограм т.е. как и везде

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

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

Да, запилили в C++11, оно работает, только никто не знает — зачем.

Ты про лямбды? Затем, чтобы упростить создание объектов-функций, когда это удобно.

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

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

Лямбды в крестах вполне юзабельны.

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

sizeof(char) по стандарту 1.

0 и 1 часто являются абсолютно нормальными в коде, при этом не являясь магическими константами. 0 используется как «false», 1 часто прибавляем для '\0' и т.п. Тут та же история char - тип базового размера, он всегда 1 и иначе быть не может.

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

0 и 1 часто являются абсолютно нормальными в коде, при этом не являясь магическими константами. 0 используется как «false», 1 часто прибавляем для '\0' и т.п. Тут та же история char - тип базового размера, он всегда 1 и иначе быть не может.

Есть принцип «явное лучше, чем неявное», говорят, что он помогает избегать багов. Но ты про него не в курсе, а сишники знамениты плодением переполнений.

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

Есть принцип «явное лучше, чем неявное», говорят, что он помогает избегать багов.

С таким принципом все ЯП с GC надо закопать.

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

С таким принципом все ЯП с GC надо закопать.

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

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

Да, запилили в C++11, оно работает, только никто не знает — зачем.

Если ты о лямбдах, то они довольно полезны. Списки захвата довольно гибки(но не без недостатков). Что тебе не нравится-то?

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

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

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

Ну да, а еще NASA, Lockheed Martin и сотни других, занимающихся серьезной разработкой. Ты и про них скажешь, что какашки, а вот хипсторский инди-гейм-гадюшник Васи Пукина - это сила?

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

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

NASA тут не очень в тему, у них стандарт несколько о другом.

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

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

Кто тебе такое сказал? Ничего гнутые ребята не инициализируют.

$ cat tst.c
#include <stdio.h>
#include <stdlib.h>

int main(){
    int* x;
    x = (int*)malloc(10*sizeof(int));
    int i;
    for(i=0; i<10; i++){
        x[i] = i;
    }
    free(x);
    x = (int*)malloc(10*sizeof(int));
    for(i=0; i<10; i++){
        printf("%d\n", x[i]);
    }
    free(x);
}
$ gcc tst.c
$ ./a.out 
0
0
2
3
4
5
6
7
8
9
Waterlaz ★★★★★
()
Ответ на: комментарий от Waterlaz

http://ideone.com/LOBsrA

А если вот так?

Зачем ты это вообще выделяешь память, если потом вообще не используешь? Тебя, кстати, не смущает, что ты выходишь за границу массива?

int* x;
x = (int*)malloc(10*sizeof(int));
int i;
for(i=0; i<10; i++){
    x[i] = i;
}
for(i=0; i<10; i++)

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

Зачем ты это вообще выделяешь память, если потом вообще не используешь?

Чтобы продемонстрировать, что ты не прав.

Тебя, кстати, не смущает, что ты выходишь за границу массива?

Не выхожу.

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

Чтобы продемонстрировать, что ты не прав.

Ты вообще понимаешь, что ты сделал? Ты выделил память для десяти интеджеров, после чего вышел за границу массива и засрал память какой-то ахинеей, после чего освободил ее. После чего ты снова делаешь тоже самое, только при этом выводишь содержимое в сосноль.

Не выхожу.

Ты выделил память для десяти чисел, а обращаясь к 10му элементы ты обращаешься к 11му числу. Ферштеин?

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

Ты вообще понимаешь, что ты сделал? Ты выделил память для десяти интеджеров, после чего вышел за границу массива и засрал память какой-то ахинеей, после чего освободил ее. После чего ты снова делаешь тоже самое, только при этом выводишь содержимое в сосноль.

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

Ты выделил память для десяти чисел, а обращаясь к 10му элементы ты обращаешься к 11му числу. Ферштеин?

Нет обращения к 10-му элементу (элементу с индексом 10), сравнение в цикле строгое.

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

Надеюсь, ты не пишешь на си. И на C++.

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

Ты выделил память для десяти чисел, а обращаясь к 10му элементы ты обращаешься к 11му числу. Ферштеин?

Допустим, первый раз ты что-то не заметил в этом коде и тебе показалось, что я там куда-то выхожу за пределы выделенной памяти, но нельзя же до сих пор продолжать нести этот бред. Прочитай еще раз, скомпилируй и запусти, подумай.

Waterlaz ★★★★★
()

Не дает покоя вопрос про обработку лшибок. В стандартной библиотеке чуть ли не каждая функция может возвращать ошибку. А Эдди сказал, что надо только malloc проверять, да и то необязательно. Мой пример с 12 страницы: Шок от С. Как склеивать строки? (комментарий)

Как вы думаете, надо ли проверять каждую функцию?

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

Угу.

#ifdef __GNUC__
#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)
#else /* __GNUC__ */
#define likely(x)       (x)
#define unlikely(x)     (x)
#endif /* __GNUC__ */
post-factum ★★★★★
()
Ответ на: комментарий от makoven

надо ли проверять каждую функцию?

Поясняю построчными комментариями:

char *get_time() {
  static const int strlen = 20;
  time_t now = time(NULL);
  if ( -1 == now) return NULL; // если не сработает, у тебя вообще система работать не будет
  struct tm *cal_now = localtime(&now);
  if (NULL == cal_now) return NULL; // будет NULL только если &now == NULL (быть такого не может), либо переполнение года (как?), 
  char *stime = malloc(strlen);
  if (NULL == stime) return NULL; // Царя на тебя не хватает ☺
  if(0 == strftime(stime, strlen, "%H:%M:%S", cal_now)){ // ХЗ, слишком длинная функция, чтобы в этой лапше что-то понять
    free(stime);
    return NULL;
  }
  return stime;
}

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

если не сработает, у тебя вообще система работать не будет

А если это какая-нибудь POSIX-совместимая ОС на микроконтроллере, которая не может в системное время?

будет NULL только если &now == NULL (быть такого не может), либо переполнение года

Из манов это неочевидно: Each of these functions returns the value described, or NULL in case an error was detected.

ХЗ, слишком длинная функция, чтобы в этой лапше что-то понять

Это вызов strftime: If the length of the result string (including the terminating null byte) would exceed max bytes, then strftime() returns 0, and the contents of the array are undefined.

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

Известно, зачем. Чтобы пополнить еще одним пунктом «не использовать ни при каких обстоятельствах» всякие coding guidelines компаний по всему миру.

дык это ИМХО лишний сахар.

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

sizeof(char) по стандарту 1

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

Если речь идет о стандарте языка программирования C:

1. Фундаментальная константа CHAR_BIT в limits.h определяет размер наименьшего объекта, не являющегося битовым полем, и имеет размер _не менее_ 8 бит.

5.2.4.2.1 Sizes of integer types <limits.h>
...
... implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.
- number of bits for smallest object that is not a bit-field (byte)
CHAR_BIT 8

2. На практике существуют платформы, на которых CHAR_BIT > 8. Пример: DSP-процессоры TI C54x. Там sizeof(char) возвращает 2.

Но если посмотреть на _другие стандарты_, то ситуация может быть иной. Например, в POSIX действительно CHAR_BIT строго равно 8.

Возможность иметь более 8 бит на char открывает путь компиляторам языка C на специфические платформы и обеспечивает его беспрецедентную распространенность. Есть овердофига умников, критикующих язык C за многочисленные implementation-defined и приводящих в пример всякие строгие недоязычки с жестко прописанными ограничениями, трансляторы которых могут зачастую существовать лишь для одной конкретной архитектуры.

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

А если это какая-нибудь POSIX-совместимая ОС на микроконтроллере, которая не может в системное время?

И там не будет функции time()? Не верю!

Из манов это неочевидно

Я по исходникам сужу. Там NULL только в этих двух случаях возвращается.

If the length of the result string (including the terminating null byte) would exceed max bytes, then strftime() returns 0, and the contents of the array are undefined

Вот, единственный косяк, который надо проверить (а то мало ли, может у тебя время в каком-нибудь сурьямьямьском языке не влезет в выделенный буфер, и его надо будет увеличить?).

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

Ты про лямбды?

нет, я про замыкания.

цитата из википедии:

В языке C++ замыкание долгое время не поддерживалось. Однако новый стандарт языка C++11 вводит лямбда-функции и выражения, ограниченно поддерживающие замыкание:

function<int()> f() {
	int x = 0;
	return [=] () mutable {return ++x; };
}
 
auto fun = f();
for (int i = 0; i < 5; ++i) {
	cout << fun() << endl;
}
emulek
()
Ответ на: комментарий от makoven

Как вы думаете, надо ли проверять каждую функцию?

Каждую. В корпоративных соглашениях о стиле часто можно встретить фразу типа «если функция возвращает диагностику, её результат обязательно должен быть обработан».

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

По поводу проверок корректности обработки даты-времени... я видел однажды афишу на сайте кинотеатра, в которой все сеансы начинались 1 января 1970 года ;)

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

Я по исходникам сужу. Там NULL только в этих двух случаях возвращается.

А потом людям приходится твой говнософт под всякими вайнами запускать.

anonymous
()

Читаю и уею. Зачем все эти ЯВУ, API и прочая дрисня, когда даже на голом асме под досом это делалось если не проще в смысле количества действий, то однозначно логичнее и интуитивнее?

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

И там не будет функции time()? Не верю!

По-моему, будет логично, если time вернет NULL если контроллер не поддерживает время

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

Ошибки в работе функции, в которой вызывается malloc() (комментарий)

Я вас огорчу, в дискуссии по вашей ссылке цитируется стандарт C++, это все-таки другой язык с более четкими ограничениями, в стандарте языка C упоминаемого раздела 5.3.3 просто нет.

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

На практике существуют платформы, на которых CHAR_BIT > 8. Пример: DSP-процессоры TI C54x. Там sizeof(char) возвращает 2.

Ты идиот, там байт - 16 бит, а sizeof(char) все так же 1.

anonymous
()

Можно еще вопрос? Делаю упражнения из туториала по libmicrohttpd.

Та же функция char *get_time(). Передаю ее в обработчик запросов через аргумент с типом void*. Потом кастую обратно.

Иными словами:

void *fp = (void *)get_time;
char *(*time)() = (char *(*)())fp;

Возможно как-то проще обратно скастовать?

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

зависит от приложения и дисциплины обработки.

твой вариант не лучший ибо хоть и прерывает штатное исполнение теряет информацию о характере препятствия.

т.е если уж проверять после каждого вызова то выставлять (тем или иным путём)(вплоть до плевка в stderr) диагностическое.

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

т.е. каждая ошибка лишь та ошибка которая валить процесс. - это кстати упрощает вопрос с утечками ибо нет долго живущих бинарей. - эдакий недоэрланг - видимо из такого подхода черпали создатели golang

да и изначальные с-сырцы очень в этом смысле прямые.

qulinxao ★★☆
()

тест(мой ИП был в списке бана почемуто для этого топика,хотя ни 1 поста не писал,если пройдет отпишу по теме)

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

Можно, если определить тип, например. Ну и явно не кастовать rvalue. Пример из моего кода:

typedef void (*dentry_handler_t)(glfs_t*, const char*, struct dirent*, struct stat*, void*);

void walk_dir_generic(glfs_t* _fs, const char* _entry_point, dentry_handler_t _handler, void* _data)
{
...
        _handler(_fs, path, entry, &sb, _data);
...
}
post-factum ★★★★★
()
Ответ на: комментарий от Eddy_Em

там ниже i-rinat правильно ответил

во первых STRLEN и РАЗМЕР по байтам строки-две разные вещи

с приходом unicode-размер чара зависит от кода символа в unicode таблице-это чар от 1 байта(ascii) 2 байта-русские 3-арабские 4-японские/китайские и до 8 байтов сейчас на 1 чар

тоесть достаточно РУССКОГО ПРОБЕЛА(символ) чтоб сломать такой код

тоесть чтоб получить размер STRLEN плюс посимвольную длину-надо составлять КАРТУ строки где будет записана длина побайтово

и после этого только-объеденять строки

и длина(в байтах) \0 символа равна длине последнего символа в строке(если в gcc собирать) либо равна длине максимально большого символа в строке(visual studio

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

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

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

Ну это понятно. Хотя в данном случае, мне кажется, достаточно проверить что возвращает get_char и если что сказать «не могу получить время».

писать всё приложение из «маленьких» самостоятельных процессов

Всмысле каждый вызов низкоуровневой функции в скрите форкает отдельный процесс?

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

Так действительно куда приятнее)

typedef char *(*get_time_t)();
get_time_t time = (get_time_t)cls;
makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от post-factum

Только strlen'у что юникод, что не-юникод — один фиг.

Ага, особенно, если юникод представлен в виде UTF-16 или UTF-32. Вообще пофиг.

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