繁体   English   中英

使用字符串文字作为使用三元运算符的表达式的结果是否有效/推荐?

[英]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 语言而言。

这是好习惯吗? 不。将字符串文字作为格式字符串传递给printfscanf等函数有几个优点。如果您传递字符串文字,编译器(和其他 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM