【发布时间】:2021-12-08 17:01:27
【问题描述】:
打印静态、无格式字符串时,C 编译器执行的常见优化之一是将printf("foobar\n"); 等调用转换为等效的puts("foobar");。只要不使用返回值,这是有效的(C 指定 printf 返回成功时写入的字符数,但 puts 仅在成功时返回非负值)。 C 编译器还会将 fprintf(stdout, "foobar") 之类的调用转换为 fwrite("foobar", 1, 6, stdout)。
但是,printf 到 puts 的优化仅适用于字符串以换行符结尾的情况,因为puts 会自动附加换行符。如果没有,我希望printf 可以优化为等效的fwrite,就像fprintf 的情况一样——但编译器似乎不这样做。比如下面的代码(Godbolt link):
#include <stdio.h>
int main() {
printf("test1\n");
printf("test2");
fprintf(stdout, "test3");
}
在汇编中针对以下调用序列进行了优化:
puts("test1");
printf("test2");
fwrite("test3", 1, 5, stdout);
我的问题是:为什么编译器在没有终止换行符的情况下不将 printf 优化为 fwrite 或类似的?这仅仅是一个错过的优化,还是printf 和fwrite 与静态、无格式字符串一起使用时存在语义差异?如果相关,我正在寻找适用于 C11 或任何更新标准的答案。
【问题讨论】:
-
“为什么编译器不优化......”更像是“为什么我测试的几个(1 或 2)个编译器没有优化......”。
-
除了在前者中使用
stdout之外,我认为fprintf(stdout, "test3");与fwrite("test3", 1, 5, stdout);与printf("test3");相比没有任何理由。 -
只是一个猜测,但我怀疑这个编译器优化领域已经很多年没有被重新审视了。我似乎记得(错误地)gcc 在没有
'\n'的情况下对文字进行了fputs()优化。但是从 gcc 7 - 11 测试后,没有进行这样的优化。printf->puts等的汇编器优化似乎是基本编译器选择,不受-Ox优化级别选择的影响。 -
ISTR 的 write 绕过了 puts 和 printf 完成的缓冲
-
@stark: POSIX
write有,但标准 Cfwrite没有。
标签: c printf language-lawyer compiler-optimization