[英]Is it valid/recommended to use string literals as the result of an expression using the ternary operator?
以下代码在 C 中是否有效/良好做法?
int x = 1;
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
它编译得很好,所以我认为它很好(也因为它只是 if-else 块的语法糖),但如果有人有一些额外的见解,我将不胜感激,谢谢。
PS,我假设 C++ 也是如此?
是的!
观点:在阅读了编写内核、驱动程序和杂项的程序员编写的大量代码之后。 通常被认为“好”的实用程序,我认为共识是“很好”。 它不仅安全 - 它还易于阅读。
一个小而无主见的注意事项:允许编译器使字符串文字重叠。 如果你有两个字符串字面量"Hello world"
和"world"
并且编译你的程序会完全优化,你可能会发现"world"
中指向'w'
的指针实际上是在"Hello world"
字符串字面量内,因为它们都是有效的、以 null 结尾的字符串。
但是,该优化不能应用于像您这样的字符串,因为不同的部分位于字符串文字的中间。
这意味着编译器必须为您的三元运算符存储两个完整的字符串,这并不比使用if
语句好。
因此我建议:
printf("%d second%s elapsed", x, x == 1 ? "" : "s");
我的另一个观点是,这样做也更容易阅读。
TL,DR:除非您真的别无选择,否则将字符串文字作为格式字符串传递。
它是否有效 C? 是的,当然。 printf
希望它的第一个参数是一个字符串(一个以空字符结尾的字符数组),它得到了它。 无论x
的值是什么,这个字符串都包含一个 printf 格式,它需要一个int
参数。 printf
接收一个int
参数。 所以一切都很好,就 C 语言而言。
这是好习惯吗? 不。将字符串文字作为格式字符串传递给printf
、 scanf
等函数有几个优点。如果您传递字符串文字,编译器(和其他 static 分析器)有机会抱怨,如果你不是通过正确键入的 arguments。 如果你传递更复杂的东西,编译器可能无法分辨。 此外,传递字符串字面量为编译器提供了更多优化机会:当格式字符串为常量时,许多编译器会将printf
调用分解为低级函数: printf("%d seconds elapsed", x)
将被编译为类似__builtin_printf_int(x) + fputs("", stdout)
(加上错误检查)。 如果格式字符串是可变的,则必须在运行时对其进行解析。
在这个简单的示例中,编译器可能会识别出只有两种可能的格式字符串并执行检查和优化。 事实上,让我们把程序弄错:
#include <stdio.h>
void foo(long x) {
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
}
这是 GCC 不得不说的:
a.c: In function ‘foo’:
a.c:3:23: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
~^
%ld
a.c:3:45: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
~^
%ld
您会收到两个警告,两种格式各有一个。 但在更复杂的情况下,编译器会放弃,只是在运行时将动态构造的字符串传递给printf
,如果参数错误,则没有机会退出。
只要您的程序为消息硬编码英语,就有一个简单的解决方案:将复数作为单独的参数。
printf("%d second%s elapsed", x, x == 1 ? "" : "s");
这不适用于国际化,因为不同的语言有不同的规则(例如,有些语言需要单数表示 0,有些语言需要不同的形式表示 2 和 3 或更多,有些语言需要“elapsed”的复数等.)。 如果您需要国际化,无论如何您都不会将常量字符串传递给printf
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.