(объединение) добавить 4 макроса "char *" вместе в C - PullRequest
0 голосов
/ 27 января 2020

У меня есть четыре char * макроса, которые я хочу собрать, но я видел ответы только с двумя char *, есть ли способ сделать это?

Вот код:

#define one   "\x0C\x03\xD1\x00"
#define two   "\xC1\x03\x1A\x0C"
#define three "\xA2\x1A\x0D\x00"
#define four  "\xD4\x1C\x4C\x0A"

char *concat(const char *s1, const char *s2, const char *s3, const char *s4) {
    char *cat = malloc(strlen(s1) + strlen(s2) + strlen(s3) + strlen(s4) + 1);
    strcpy(cat, s1);
    strcpy(cat, s2);
    strcpy(cat, s3);
    strcat(cat, s4);
    return cat;
}

Ответы [ 3 ]

1 голос
/ 27 января 2020

Поскольку one, two, three, four - это макросы, расширяющиеся непосредственно до строковых констант, вы можете просто сделать это:

char result[] = one two three four;

После расширения макроса оно превратится в

char result[] = "\x0C\x03\xD1\x00" "\xC1\x03\x1A\x0C" "\xA2\x1A\x0D\x00" "\xD4\x1C\x4C\x0A";

и смежные строковые литералы объединяются автоматически.

Обратите внимание, что это не будет работать, если вы заменяете макросы переменными, например char *one = "\x0C\x03\xD1\x00";.

Для более общих подходов о конкатенации произвольных строк (не обязательно макросов), см. другие ответы.

1 голос
/ 27 января 2020

Учитывая наличие символов NUL, они не являются строками (так как они заканчиваются NUL), поэтому строковые функции, такие как strlen, не могут использоваться, поэтому размеры массивов необходимо будет передавать в объединяющая функция.

 char *buf_concat(
    char **buf_ptr, size_t *size_ptr,
    const char *buf1, size_t n1,
    const char *buf2, size_t n2,
    const char *buf3, size_t n3,
    const char *buf4, size_t n4
 ) {
    *size_ptr = n1+n2+n3+n4;
    char *buf_ptr; = malloc(*size_ptr);
    if (!*buf_ptr)
       return NULL;

    char *p = *buf_ptr;
    memcpy(p, buf1, n1);  p += n1;
    memcpy(p, buf2, n2);  p += n2;
    memcpy(p, buf3, n3);  p += n3;
    memcpy(p, buf4, n4);
    return *buf_ptr;
 }

 char *buf;
 size_t buf_size;
 buf_concat(
    &buf,  &buf_size,
    one,   sizeof(one  )-1,
    two,   sizeof(two  )-1,
    three, sizeof(three)-1,
    four,  sizeof(four )-1
 );

(Мы должны вычесть 1, потому что sizeof("\xC1\x03\x1A\x0C") - это 5.)

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

 size_t buf_size =
      sizeof(one  )-1
    + sizeof(two  )-1
    + sizeof(three)-1
    + sizeof(four )-1;

 char *buf = malloc(buf_size);
 char *p = buf;
 memcpy(p, one,   sizeof(one  )-1);  p += sizeof(one  )-1;
 memcpy(p, two,   sizeof(two  )-1);  p += sizeof(two  )-1;
 memcpy(p, three, sizeof(three)-1);  p += sizeof(three)-1;
 memcpy(p, four,  sizeof(four )-1);

Но поскольку "aaa" "bbb" - это то же самое, что и "aaabbb", мы можем упростить !

 size_t buf_size = sizeof(one two three four) - 1;
 char *buf = malloc(buf_size);
 memcpy(buf, one two three four, buf_size);

(Спасибо @ chqrl ie за напоминание, что я все время хотел упомянуть этот ярлык!)

1 голос
/ 27 января 2020

Например, в вашей реализации функции второй вызов strcpy перезаписывает первую строку в массиве, на которую указывает переменная cat.

strcpy (cat, s1); strcpy (cat, s2);

Я думаю, вы имеете в виду следующее

char * concat(const char * s1, const char * s2, const char * s3, const char * s4) {
  char * cat = malloc(strlen(s1)+strlen(s2)+strlen(s3)+strlen(s4)+1);

  strcpy( cat, s1 );
  strcat( cat, s2 );
  strcat( cat, s3 );
  strcat( cat, s4 );

  return cat;
}

Более эффективным подходом является следующий

char * concat(const char * s1, const char * s2, const char * s3, const char * s4) {
  size_t n1 = strlen( s1 );
  size_t n2 = strlen( s2 ); 
  size_t n3 = strlen( s3 ); 
  size_t n4 = strlen( s4 );

  char *cat = malloc( n1 + n2 + n3 + n4 + 1 );

  strcpy( cat, s1 );
  strcpy( cat + n1, s2 );
  strcpy( cat + n1 + n2, s3 );
  strcpy( cat + n1 + n2 + n3, s4 );

  return cat;
}

Что касается этих макросов

#define one   "\x0C\x03\xD1\x00"
#define two   "\xC1\x03\x1A\x0C"
#define three "\xA2\x1A\x0D\x00"
#define four  "\xD4\x1C\x4C\x0A"

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

char * concat(const char * s1, const char * s2, const char * s3, const char * s4, size_t n )
{
    size_t length = 4 * n + 1;

    char * cat = malloc( length );

    memcpy( cat, s1, n );
    memcpy( cat + n, s2, n );
    memcpy( cat + 2 *n, s3, n );
    memcpy( cat + 3 *n, s4, n );
    cat[4 & n] = '\0';

    return cat;
}

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

...