LINUX.ORG.RU

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

 


13

7

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

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

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

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

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

★★★★★

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

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

На самом деле использовать C++ легче, начинать с него легче.

Вот та же исходная задача в C++ уже решена - тебе останется написать s1 + s2. Если вдруг это станет узким местом(а не станет, я тебя уверяют), перепишешь на что-то более оптимальное(тут C++ не проиграет С).

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

Возьмём обобщенный код. Структуры данных, алгоритмы, вот это все. В C++ ты возьмёшь шаблоны и спокойно напишешь код, почти так же, как ты пишешь обычные структуры/классы, функции/методы. В си тебе или придёться копипастить код и менять типы, или писать генераторы, или обмазаться макросами, или использовать void*, получив оверхед на ровном месте.

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

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

И т.д. и т.п.

anonymous
()
Ответ на: Не хуже от Camel

Покажи мне, что на C++ решается хуже, чем на си? Ну кроме отсутствия компилятора и пр. инфраструктурных проблем.

anonymous
()
Ответ на: Нужно от Camel

На C++ не нужно писать как на C.

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

Не понимаю...

Еще бы на жабке числодробилки писали... Ужас!

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

что на C++ решается хуже, чем на си?

Некоторые дебилоиды и под микроконтроллеры на С++ пишут, в итоге хеллоуворлд в 8КБ не влезает...ж

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

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

В этих условиях С++ все равно оказывается удобнее Си(RAII, перегрузка функций, вывод типов и пр.).

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

RTOS

Покажи мне, что на C++ решается хуже, чем на си?

Hard real time.

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

Некоторые дебилоиды и под микроконтроллеры на С++ пишут, в итоге хеллоуворлд в 8КБ не влезает...ж

Ты что-то с чем-то путаешь. Во-первых хеллоуворлд и на С в 8Кб уже не влезет. Это если говорить про gcc + elf, например. А на С++ под микроконтроллеры можно практически полноценный HTTP сервер в 8Кб вместить. Со всеми фишками С++, кроме всяких там std::, ес-но.

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

Да что ты говоришь! Просто не нужно stdlib использовать!

Я тебе о том же и говорю. Не используй libstdc++ - и получишь компактный выхлоп.

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

Под RAII имеются в виду писать деструкторы для классов?

Возьмём обработку ошибок.

А вот этот мужчина очень сильно ругается на исключения. И на невозможность их отключить

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

Только черт ногу сломит в этом С++.

Зачем усложнять?

Проще С может быть только ассемблер, но на ассемблере писанины слишком много.

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

я ему с самого начала говорил, что можно в поток выводить, или при помощи fprintf()/sprintf() в формате:

fprintf(stdout, "%s%s\n", string, string2);

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

А вот этот мужчина очень сильно ругается на исключения. И на невозможность их отключить

Я тоже не использую исключения для обработки ошибок. А вот для того, чтоб оборвать парсер, например, это самое то. Т.е. они хорошо подходят для внутренней реализации, а не для того, чтоб сообщать наверх «пользователю» об ошибках. Такой себе высокоуровневый «longjmp». Ес-но это мое личное мнение, хотя в С++ обычно исключения редко используют.

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

Я не вкурсе, а в STL разве исключения не используются? К тому, что если в плюсовых библиотеках есть исключения - хочешь-нехочшь придется писать в их стиле

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

Зачем усложнять?

Данный топик показывает обратное. Простое a + b в С++ превращается в массу вариантов на С разной степени кривости.

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

Я не вкурсе, а в STL разве исключения не используются

очень и очень редко, например, в std::vector::at, но практически все пользуют operator[], т.к. в нем нет оверхеда на проверку

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

Обычно их нет. По-крайней мере в популярных.

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

Простое a + b в С++

Это извращение — обзывать конкатенацию двух больших кусков памяти знаком "+". Ничего общего со сложением эта операция не имеет.

В С все логично делается, а в извращенном С++ с его перегруженными операторами черт ногу сломит!

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

Во-первых хеллоуворлд и на С в 8Кб уже не влезет

Да что ты говоришь! Просто не нужно stdlib использовать!

до какого размера ты можешь уменьшить хеловорлд на си?

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

Зависит от микроконтроллера: инициализация периферии у всех разная.

На какой-нибудь элементарный STM8 вот такой хеллоуворлд занял 680 байт:

void uart_write(char *str){
    while(*str){
        UART2_DR = *str++;
        while(!(UART2_SR & UART_SR_TC));
    }
}

int main(){
    // Configure pins
    // PD5 - UART2_TX -- pseudo open-drain output; don't forget an pullup resistor!
    PORT(UART_PORT, DDR) |= UART_TX_PIN;
    PORT(UART_PORT, ODR) &= ~UART_TX_PIN; // turn off N push-down
    // Configure UART
    // 9 bit, no parity, 1 stop (UART_CR3 = 0 - reset value)
    // 57600 on 16MHz: BRR1=0x11, BRR2=0x06
    UART2_BRR1 = 0x11; UART2_BRR2 = 0x06;
    UART2_CR1  = UART_CR1_M; // M = 1 -- 9bits
    UART2_CR2  = UART_CR2_TEN | UART_CR2_REN | UART_CR2_RIEN; // Allow RX, generate ints on rx

    do{
        uart_write("Hello world!");
    }while(1);
}
но тут sdcc используется, gcc не умеет 8-битные, к сожалению. А gcc мог бы и сильней ужать.

В принципе, можно было бы под STM32F030 попробовать подобное сделать, но лень мне сейчас клепать тест.

Eddy_Em ☆☆☆☆☆
()

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

realloc + memcpy

/thread

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

Это извращение — обзывать конкатенацию двух больших кусков памяти знаком «+». Ничего общего со сложением эта операция не имеет.

окей:

a.append( b );

а в извращенном С++ с его перегруженными операторами черт ногу сломит!

в реальности все не так страшно

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

А на С++ под микроконтроллеры можно практически полноценный HTTP сервер в 8Кб вместить

Пример в студию!

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

Хотел наглядно показать, почему... но оно даже не работает.

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

char * strapp(const char *first, const char *second) {
    size_t bytesCount = sizeof(char) * (strlen(first) + strlen(second));
    char *dest;

    /* returns NULL if malloc() fails */
    if(dest = malloc(bytesCount)) {
        memset(dest, 0, bytesCount);
        strcat(strcat(dest, first), second);
    }

    return dest;
}

char *genrandstr(int L){
    int i;
    char *ret = malloc(L+1);
    if(!ret) return NULL;
    for(i = 0; i < L; i++){
        ret[i] = 32 + (rand() % 95);
    }
    ret[L] = 0;
    return ret;
}

int main(){
  char *s;
  int i;
  srand(time(NULL));
  s = genrandstr(rand() % 1014 + 10);
  if(!s) return -3;
  for(i = 0; i < 1000; ++i){
    char *randstr = genrandstr(rand() % 1014 + 10);
    if(!randstr) return -1;
    if(!(s = strapp(s, randstr))) return -2;
    free(randstr);
    printf("got: %s\n\n",s);
  }
  printf("%s\n", s);
  return 0;
}
$ time for i in $(seq 1 10); do ./test2c > /dev/null; done
Segmentation fault (core dumped)
...

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

a.append( b );

Вот так нормально. Это можно и в сях сделать.

в реальности все не так страшно

А у меня до сих пор глаз дергается от упоминания С++. Нанесенная травма глубока...

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

Однако все-же много строк писать приходится. Намедни писал функцию, возвращающую строку со временем:

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;
  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;
}
makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от CYB3R

Пример в студию!

код проприетарный, показать не могу, 8Кб - это ес-но сам блоб, еще дополнительно используется память стека под данные, парсится все в том же буфере без дополнительных выделений памяти, никаких std::string - только char*, только хардкор, так и быстрее и опять же память дополнительная не нужна

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

Это можно и в сях сделать.

Если точно известно, что строка выделена на куче, а если передать указатель на строку в стеке - будет жопа. В С++ за такое отвечает аллокатор и std::string::append все-равно кем и как выделена строка. Хоть malloc, хоть alloca, хоть свой пул.

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

std::string::append

а точнее std::basic_string::append

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

Если точно известно, что строка выделена на куче, а если передать указатель на строку в стеке - будет жопа

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

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

Здравый смысл подсказывал, что врят-ли время поломается. Но в манах неумолимо «если фейл - верну NULL/-1»

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

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

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

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

Это можно и в сях сделать

Но за 40 лет не сделано и не принято в стандарт.

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

А что там удивительного? Простой http сервер это около 1к строчек чистого C + функции ввода-вывода.

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/appl... смотреть foot print information

Если поискать на st.com STSW-STM32060 то будут и исходники.

Для сравнения - простая реализация STL для embedded - 17k строк

stlport 48k строк. В отличии от сишного кода темплейты могу раздуются с каждым использованным типом в бинарнике.

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

этот мужчина, видимо, не умеет в си-плюс-плюс

anonymous
()

Подскажите, что я не так делаю?

int f (char *s){
  puts(s);
  return 0;
}

int main(int argc, char **argv) {
  int (fp)(char *);
  fp = f;
  fp("Hello");
}
temp.c:12:6: error: non-object type 'int (char *)' is not assignable
  fp = f;
  ~~ ^
makoven ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

страуструп кресты придумал как раз для проектов овер 9000 лок, которые пишут несколько человек

anonymous
()
Ответ на: комментарий от makoven
char *
get_time()
{
#define SAFECALL(STMT, ERVAL, FREE) do { if ((STMT) == ERVAL) { FREE; return NULL; } } while (0)

        char *stime = NULL;
        static const int strlen = 20;
        time_t now;
        struct tm *cal_now;

        SAFECALL( now = time(NULL), -1,                            (void)stime);
        SAFECALL( cal_now = localtime(&now), NULL,                 (void)stime);
        SAFECALL( stime = malloc(strlen), NULL,                    (void)stime);
        SAFECALL( strftime(stime, strlen, "%H:%M:%S", cal_now), 0, free(stime));
        return stime;

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

первоклассные функции в си? прохладная история.

через указатель можно

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

Вспомнилась игрушка http://www.kongregate.com/games/coolio_niato/light-bot

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

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

Под RAII имеются в виду писать деструкторы для классов?

Сам принцип заключается в том, что у ресурсов есть владелец(или несколько владельцев). Да, в деструкторе мы освобождаем ресурс/уменьшаем счетчик ссылок на него и пр. и пр. А благодаря автоматическому вызову деструкторов в C++, мы избавляемся от явных ручных вызовов. В Си можно добиться этого с помощью некоторых плюшек gcc и __try __finally в оффтопике, навернув над этим делом макросов. Но это будет непереносимым костылем.

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