为什么C在使用三元运算符时不允许连接字符串?

以下代码编译没有问题:

int main() {
    printf("Hi" "Bye");
}

但是,这不编译:

int main() {
    int test = 0;
    printf("Hi" (test ? "Bye" : "Goodbye"));
}

这是什么原因?

José D. asked 2019-08-13T14:09:59Z
8个解决方案
133 votes

根据C11标准,章节§5.1.1.2,相邻字符串文字的连接:

相邻的字符串文字标记是连接的。

发生在翻译阶段。 另一方面:

printf("Hi" (test ? "Bye" : "Goodbye"));

涉及条件运算符,它在运行时进行评估。 因此,在编译时,在转换阶段,不存在相邻的字符串文字,因此连接是不可能的。 语法无效,因此由编译器报告。


为了详细说明原因部分,在预处理阶段,相邻的字符串文字被连接起来并表示为单个字符串文字(标记)。 相应地分配存储,并且连接的字符串文字被视为单个实体(一个字符串文字)。

另一方面,在运行时连接的情况下,目标应该有足够的内存来保存连接的字符串文字,否则将无法访问预期的连接输出。 现在,在字符串文字的情况下,它们已经在编译时分配了内存,并且无法扩展以适应原始内容中的任何更多传入输入或附加到原始内容。 换句话说,无法将连接结果作为单个字符串文字进行访问(呈现)。 所以,这种结构固有地不正确。

仅供参考,对于运行时字符串(不是文字)连接,我们有库函数s1,它连接两个字符串。 注意,描述中提到:

s1

s1函数附加s2指向的字符串的副本(包括   终止空字符)到s1指向的字符串的末尾。初始字符   s2的全部内容将覆盖s1结尾处的空字符。[...]

所以,我们可以看到,s1是一个字符串,而不是字符串文字。 但是,由于s2的内容没有以任何方式改变,因此很可能是字符串文字。

Sourav Ghosh answered 2019-08-13T14:12:37Z
119 votes

根据C标准(5.1.1.2翻译阶段)

1翻译语法规则的优先级由   以下阶段.6)

  1. 相邻的字符串文字标记是连接的。

只有在那之后

  1. 分隔标记的空白字符不再重要。 每   预处理令牌转换为令牌。 所结果的   令牌在语法和语义上被分析并翻译为   翻译单位。

在这种结构中

"Hi" (test ? "Bye" : "Goodbye")

没有相邻的字符串文字标记。 所以这种结构无效。

Vlad from Moscow answered 2019-08-13T14:11:04Z
38 votes

字符串文字串联由预处理器在编译时执行。 这种连接无法识别strcat的值,这在程序实际执行之前是未知的。 因此,这些字符串文字不能连接。

因为一般情况下,对于编译时已知的值,你不会有这样的结构,C标准被设计为将自动连接功能限制为最基本的情况:当文字在字面上是正确的时候 彼此。

但即使它没有以这种方式说明这种限制,或者如果限制是不同构造的,如果不将连接作为运行时进程,你的例子仍然是不可能实现的。 而且,为此,我们有库函数,如strcat

Lightness Races in Orbit answered 2019-08-13T14:13:20Z
30 votes

因为C没有?类型。 字符串文字被编译为char数组,由char*指针引用。

C允许在编译时组合相邻的文字,如第一个示例中所示。 C编译器本身对字符串有一些了解。 但是这些信息在运行时不存在,因此不能进行连接。

在编译过程中,您的第一个例子是"翻译" 至:

int main() {
    static const char char_ptr_1[] = {'H', 'i', 'B', 'y', 'e', '\0'};
    printf(char_ptr_1);
}

请注意编译器在执行程序之前如何将两个字符串组合到单个静态数组中。

但是,你的第二个例子是"翻译" 这样的事情:

int main() {
    static const char char_ptr_1[] = {'H', 'i', '\0'};
    static const char char_ptr_2[] = {'B', 'y', 'e', '\0'};
    static const char char_ptr_3[] = {'G', 'o', 'o', 'd', 'b', 'y', 'e', '\0'};
    int test = 0;
    printf(char_ptr_1 (test ? char_ptr_2 : char_ptr_3));
}

应该清楚为什么这不编译。 三元运算符?在运行时进行评估,而不是编译时,当"字符串" 不再存在,但仅仅是char*指针引用的数组,由char*指针引用。 与相邻的字符串文字不同,相邻的char指针只是语法错误。

Unsigned answered 2019-08-13T14:14:27Z
13 votes

如果你真的想让两个分支都产生在运行时选择的编译时字符串常量,那么你需要一个宏。

#include <stdio.h>
#define ccat(s, t, a, b) ((t)?(s a):(s b))

int
main ( int argc, char **argv){
  printf("%s\n", ccat("hello ", argc > 2 , "y'all", "you"));
  return 0;
}
Eric answered 2019-08-13T14:14:54Z
9 votes

这是什么原因?

使用三元运算符的代码有条件地在两个字符串文字之间进行选择。 无论条件是已知的还是未知的,都无法在编译时对其进行评估,因此无法进行编译。 即使这个声明printf("Hi" (1 ? "Bye" : "Goodbye"));也不会编译。 原因在上面的答案中深入解释。 使用三元运算符有效编译这种语句的另一种可能性还包括格式标记和三元运算符语句的结果,格式化为printf的附加参数。即便如此,printf()打印输出会给人一种印象:&#34;级联&#34; 这些字符串仅在运行时和早期运行时。

#include <stdio.h>

int main() {
    int test = 0;
    printf("Hi %s\n", (test ? "Bye" : "Goodbye")); //specify format and print as result
}
user3078414 answered 2019-08-13T14:15:27Z
8 votes

printf("Hi" (test ? "Bye" : "Goodbye"));中,您有两个连续的char数组,编译器可以将它们组成一个数组。

printf("Hi" (test ? "Bye" : "Goodbye"));中,您有一个数组,后跟一个指向char的指针(一个数组转换为指向其第一个元素的指针)。 编译器无法合并数组和指针。

pmg answered 2019-08-13T14:16:07Z
-3 votes

这不会编译,因为printf函数的参数列表是

(const char *format, ...)

("Hi" (test ? "Bye" : "Goodbye"))

不适合参数列表。

gcc试图通过想象来理解它

(test ? "Bye" : "Goodbye")

是一个参数列表,并抱怨&#34;嗨&#34; 不是一个功能。

Rodbots answered 2019-08-13T14:17:01Z
translate from https://stackoverflow.com:/questions/37259472/why-does-c-not-allow-concatenating-strings-when-using-the-ternary-operator