Конкатенация строкового литерала с символьным литералом - PullRequest
10 голосов
/ 28 марта 2012

Я хочу объединить строковый литерал и символьный литерал.Синтаксически некорректно, "abc" 'd' "efg" выдает ошибку компилятора:

xc: 4: 24: ошибка: ожидается ',' или ';'до 'd'

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

Я пытался

#define CONCAT(S,C) ({ \
    static const char *_r = { (S), (C) }; \
    _r; \
})

но это не работает, потому что нулевой терминатор S не удаляется.(Помимо выдачи предупреждений компилятора.)

Есть ли способ написать макрос для использования

  • "abc" MACRO('d') "efg" или
  • MACRO1(MACRO2("abc", 'd'), "efg") или
  • MACRO("abc", 'd', "efg")?

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

Ответы [ 4 ]

6 голосов
/ 28 марта 2012

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

#define SOME_DEF 'x'

#define STR1(z) #z
#define STR(z) STR1(z)
#define JOIN(a,b,c) a STR(b) c

int main(void)
{
  const char *msg = JOIN("Something to do with ", SOME_DEF, "...");

  puts(msg);

  return 0;
}

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

3 голосов
/ 29 марта 2012

Я придумал решение для GCC, которое мне не очень нравится, поскольку нельзя использовать CONCAT вложенно.

#include <stdio.h>

#define CONCAT(S1,C,S2) ({                        \
    static const struct __attribute__((packed)) { \
        char s1[sizeof(S1) - 1];                  \
        char c;                                   \
        char s2[sizeof(S2)];                      \
    } _r = { (S1), (C), (S2) };                   \
    (const char *) &_r;                           \
})

int main(void) {
    puts(CONCAT ("abc", 'd', "efg"));
    return 0;
}

http://ideone.com/lzEAn

3 голосов
/ 28 марта 2012

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

2 голосов
/ 28 марта 2012

C позволит вам объединять только строковые литералы. На самом деле, нет ничего плохого в snprintf(). Вы также можете использовать strcpy():

strcpy(dest, str1);
dest[strlen(dest)] = c;
strcpy(dest + strlen(dest) + 1, str2);

Вы также можете использовать гигантское выражение switch, чтобы преодолеть это ограничение:

switch(c) {
    case 'a':
        puts("part1" "a" "part2");
        break;
    case 'b':
        puts("part1" "b" "part2");
        break;

    /* ... */

    case 'z':
        puts("part1" "z" "part2");
        break;
}

... но я отказываюсь претендовать на авторство.

Короче говоря, просто придерживайтесь snprintf().

...