连接字符串文字与字符文字

11

我希望将一个字符串字面量和字符字面值连接起来。语法不正确,"abc" 'd' "efg"会导致编译错误:

x.c:4:24: error: expected ',' or ';' before '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 文字来自库文件,我需要将字符串作为状态消息打印出来。


我不想使用sprintf或任何运行时函数。请不要提供任何使用运行时方法调用的答案。 - Kijewski
如果字面量来自库,那么你如何访问它?它是由库头文件提供的宏吗? - John Bode
是的,它来自一个头文件。 - Kijewski
相关:https://dev59.com/GIPba4cB1Zd3GeqPyeOk - martinkunev
4个回答

7

如果您可以接受包含单引号,您可以使用字符串化:

#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;
}

根据上下文的不同,这种做法可能或可能不合适,但是如果要说服它实际上是以这种方式构建的字符串字面量,则没有其他方法可以想到,而不需要在运行时进行格式化。


1
为什么不直接在连接中使用STR1,例如JOIN(a,b,c) a STR1(b) c?而不是使用子宏STR()? - Luciano
1
@Luciano 因为这样它会显示为“与SOME_DEF有关的某些事情...” - S.S. Anne

3

试一下这个。它使用C宏的双重宏技巧,以便在字符串化之前宏参数有机会扩展。

#include <stdio.h>

#define C d
#define S "This is a string that contains the character "
#define STR(s) #s
#define XSTR(s) STR(s)

const char* str = S XSTR(C);

int main()
{
    puts(str);
    return 0;
}

3
我想出了一个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


1
好主意,但使用gcc编译时加上-pedantic选项会出现警告:“数组从带括号的字符串常量初始化”和“ISO C禁止在表达式中使用大括号组”。 - Adam Rosenfield

2

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()


问题在于我不想使用snprintf或strcpy。这更像是一个哲学问题,而不是初学者的问题... - Kijewski
1
Kay:啊,我明白了...祝你好运! ;) 顺便问一下,printf("part1 %c part2\n", c);有什么问题吗? - Philip
1
printf 没有任何“问题”。我只是想知道是否可能在编译时获得整个字符串,而不需要任何运行时活动。是否有这样的宏并不重要。你看……这是一个哲学问题。 ;) - Kijewski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接