int main() {
printf("Hi" "Bye");
}
然而,这个代码不能编译:
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
那个原因是什么?int main() {
printf("Hi" "Bye");
}
然而,这个代码不能编译:
int main() {
int test = 0;
printf("Hi" (test ? "Bye" : "Goodbye"));
}
那个原因是什么?printf("Hi" (test ? "Bye" : "Goodbye"));
strcat()
,它将两个字符串连接起来。请注意,描述中提到:
因此,我们可以看到,
char *strcat(char * restrict s1,const char * restrict s2);
strcat()
函数将指向s2
指向的字符串(包括结尾的空字符)的副本附加到指向s1
的字符串的末尾。s2
的初始字符覆盖s1
末尾的空字符。[...]
s1
是一个字符串,而不是字符串字面量。但是,由于s2
的内容没有以任何方式更改,因此它很可能是字符串字面量。strcat
进行额外的解释:目标数组必须足够长,以接收s2
中的字符以及已经存在的字符后面的空终止符。 - chqrlie根据C标准(5.1.1.2翻译阶段)
1 翻译中语法规则的优先级由以下阶段指定。6)
- 相邻的字符串字面量记号被连接。
仅在此之后
- 分隔标记的空格字符不再具有意义。每个预处理记号都转换为一个记号。生成的记号作为翻译单元进行语法和语义分析并翻译。
在这个结构中
"Hi" (test ? "Bye" : "Goodbye")
没有相邻的字符串字面量标记,因此这个结构是无效的。
(test ? "Bye" : "Goodbye")
不能评估为任何一个字符串字面值,从而使得"Hi" "Bye"
或者"Hi Goodbye"
呢?(我的问题已经在其他答案中得到了解答) - Insane字符串字面量的拼接是在编译时由预处理器执行的。这种拼接无法意识到test
的值,因为该值直到程序实际执行时才能确定。因此,这些字符串字面量无法被连接。
因为通常情况下,你不会在编译时就知道需要拼接哪些值,所以C标准将自动拼接功能限制为最基本的情况:当字面量直接相邻时。
但即使它没有以那种方式表达这种限制,或者如果限制是不同构造的,你的示例仍然无法实现,除非将拼接过程变成运行时的。为此,我们有像strcat
这样的库函数。
由于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
数组存在。相邻的 字符串字面量 不同于相邻的 字符指针,后者只是语法错误。static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
这句话不应该是 static const char *char_ptr_1 = "HiBye";
吗?其他指针也应该类似。 - Spikatrixstatic const char *char_ptr_1 = "HiBye";
时,编译器会将该行翻译为 static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
,因此不应该像字符串一样写。正如答案所说,字符串被编译为字符数组,如果你要将一个字符数组以最“原始”的形式赋值,你需要使用逗号分隔的字符列表,就像 static const char *char_ptr_1 = {'H', 'i', 'B', 'y', 'e', '\0'};
。 - Ankushstatic const char str[] = {'t', 'e', 's', 't', '\0'};
和 static const char str[] = "test";
一样,static const char* ptr = "test";
却 不同于 static const char* ptr = {'t', 'e', 's', 't', '\0'};
。前者是有效的且可以编译,但后者无效且不会产生预期结果。 - Spikatrix如果您真的想让两个分支都生成在运行时选择的编译时字符串常量,那么您需要使用宏。
#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;
}
为什么会这样呢?
您的代码使用三元运算符在两个字符串文本之间进行有条件选择。无论条件是已知还是未知,都无法在编译时评估,因此无法编译。即使此语句printf("Hi" (1 ? "Bye" : "Goodbye"));
也不会编译。原因在上面的答案中有详细解释。 要想使用三元运算符使得此类语句有效地编译,需要使用格式标记和将三元运算符语句的结果格式化为附加参数传递给printf
。即使如此,printf()
打印出来的效果也只是在运行时尽早地“连接”这些字符串。
#include <stdio.h>
int main() {
int test = 0;
printf("Hi %s\n", (test ? "Bye" : "Goodbye")); //specify format and print as result
}
printf
不需要格式说明符;如果只有在编译时进行连接(实际上并不是这样),那么 OP 使用 printf 的方式就是有效的。 - David Conradprintf()
需要一个格式标签,这是绝对不正确的。已经更正! - user3078414printf("Hi" "Bye");
中,你有两个连续的字符数组,编译器可以将它们合并成一个单独的数组。printf("Hi" (test ? "Bye" : "Goodbye"));
中,你有一个数组后面跟着一个指向字符的指针(将一个数组转换为指向其第一个元素的指针)。编译器无法合并一个数组和一个指针。回答这个问题 - 我会去查找printf的定义。函数printf期望const char*作为参数。任何字符串字面量,例如“Hi”都是const char*; 但是像(test)? "str1" : "str2"
这样的表达式不是const char*,因为这种表达式的结果只能在运行时确定,在编译时是不确定的,这正是导致编译器抱怨的原因。另一方面 - 这个可以完美地工作:printf("hi %s", test? "yes":"no")
(test)? "str1" : "str2"
这样的表达式并不是const char *
...当然它不是一个常量表达式,但它的类型确实是const char *
。写printf(test ? "hi " "yes" : "hi " "no")
是完全可以的。OP的问题与printf
无关,"Hi" (test ? "Bye" : "Goodbye")
无论在什么表达式上下文中都是语法错误。 - chqrlie这段代码无法编译,因为printf函数的参数列表不正确。
(const char *format, ...)
并且
("Hi" (test ? "Bye" : "Goodbye"))
不符合参数列表。
gcc试图通过想象来理解它。
(test ? "Bye" : "Goodbye")
这是一个参数列表,并且抱怨“Hi”不是一个函数。
printf()
的参数列表不匹配,但这是因为该表达式无效,不仅在 printf()
的参数列表中无效,在任何地方都无效。换句话说,你选择的问题原因过于特定,一般性问题是 "Hi" (
在 C 语言中无效,更不用说作为 printf()
的调用了。我建议在被踩之前删除这个答案。 - Jonathan Leffler
"Hi"
和"Bye"
是字符串字面量,而不是C标准库中使用的字符串。使用字符串字面量,编译器将连接"H\0i" "B\0ye"
。但是sprintf(buf,"%s%s", "H\0i" "B\0ye");
则不同。 - chux - Reinstate Monicaa (some_condition ? + : - ) b
。 - user253751printf("Hi" ("Bye"));
也不起作用——它不需要三元运算符;括号就足够了(尽管printf("Hi" test ? "Bye" : "Goodbye")
也无法编译)。只有有限数量的标记可以跟随字符串字面值。逗号,
、开方括号[
、闭方括号]
(如1["abc"]
——是可怕的),闭圆括号)
、闭花括号}
(在初始化程序或类似上下文中),以及分号;
是合法的(和另一个字符串字面值);我不确定是否还有其他的。 - Jonathan Leffler