在列印靜態、無格式字串時,C 編譯器執行的常見優化之一是將呼叫printf("foobar\n");轉換為等效的puts("foobar");. 只要不使用回傳值,這就是有效的(C 指定printf在成功時puts回傳寫入的字符數,但僅在成功時回傳非負值)。C 編譯器還會將呼叫轉換fprintf(stdout, "foobar")為fwrite("foobar", 1, 6, stdout).
但是,printftoputs優化僅適用于字串以換行符結尾的情況,因為會puts自動附加換行符。如果沒有,我希望printf可以優化為等效的fwrite,就像這種fprintf情況一樣 - 但似乎編譯器不會這樣做。例如,以下代碼(Godbolt 鏈接):
#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 或任何更新標準的答案。
uj5u.com熱心網友回復:
這只是一個錯過的優化——編譯器沒有理由不能完成你想象的轉換——但這是一個有動機的優化。編譯器將呼叫printf轉換為呼叫puts比呼叫fputsor容易得多fwrite,因為后兩者需要編譯器stdout作為引數提供。 stdout是一個宏,當編譯器開始進行庫呼叫優化時,宏定義可能不再可用(即使集成了前處理器),或者可能無法再將令牌序列決議為 AST 片段。
相比之下,編譯器可以很容易地fprintf變成fputs,因為它也可以使用提供的任何內容作為呼叫with的 FILE*引數。但是我不會對一個可以變成但不能變成...的編譯器感到驚訝,因為它無法知道這個呼叫的第一個引數是stdout。(請記住,此優化程序與 IR 等價物或類似物一起使用。)fprintffputsfprintf(stdout, "blah\n")fputs("blah\n", stdout)puts("blah")fprintf&_iob[1]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/331919.html
上一篇:模數索引對性能有巨大影響
