[英]Why didn't GCC optimize this 'printf' to 'puts'?
這是我的測試代碼:
#include<stdio.h>
static inline void foo(int a){
printf("%x\n", a);
}
int main(void){
foo(0x1234);
return 0;
}
我認為GCC應該意識到a
是一個文字整數,並優化代碼如下:
puts("1234");
但是我得到了以下匯編代碼:
│0x8048341 <main+17> push $0x1234
│0x8048346 <main+22> push $0x80484e0
│0x804834b <main+27> push $0x1
│0x804834d <main+29> call 0x8048310 <__printf_chk@plt>
在我的項目中存在很多這樣的代碼,因為我一直認為GCC會為我優化,甚至在某些可以簡單地使用'write()'的上下文中,我堅持使用printf
,因為我認為我會從中受益它的緩沖機制。
現在我感到遺憾,因為削減格式字符串的開銷會殺死我的任何收益。 我項目中的這些代碼非常低級,可能會導致性能瓶頸。
我項目中的這些代碼非常低級,可能會導致性能瓶頸。
首先,我可以減輕你的擔心,這是不可能的。 控制台I / O的開銷是巨大的 (相對而言),因此無論您使用何種方式,它始終是代碼中的瓶頸。
我認為gcc應該意識到
a
是一個文字整數,並優化代碼如下:puts("1234");
顯然它沒有。 GCC(和Clang) 確實在printf("...\\n");
變成了puts("...");
,正如你在這里看到的那樣,但這只有在你使用printf
字符串文字時才會發生。 優化器(目前)不會查看格式字符串,解析它並圍繞它進行優化。 你打電話給printf
,所以你得到printf
。
無法保證編譯器優化,因此如果沒有首先驗證所期望的優化實際上是在您感興趣的所有情況下應用(包括代碼變體,編譯器版本,目標平台等),則不應編寫依賴於它們的代碼。 )。
如果您想將此建議作為GCC優化器的可能改進,您可以建議對其Bugzilla進行增強。 但是,不要在適應的時候盡快屏住呼吸。 實現這種類型的優化所需的邏輯並不值得付出努力,考慮到可以預期的實際性能改進最多是最小的(見上文)。
與此同時,如果您絕對需要對代碼進行最少的更改來進行此優化,那么您可以使用一些宏hackery :
#define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
#define foo(a) puts(STRINGIFY(a))
這確實產生了所需的輸出:
.LC0:
.string "0x1234"
MyFunction:
sub esp, 24
push OFFSET FLAT:.LC0
call puts
xor eax, eax
add esp, 28
ret
符合標准的庫實現可以包括標准定義的函數,這將改變標准函數的行為方式。 例如,庫可能包含__select_alternate_digits
函數,該函數在調用時會導致對printf
后續調用使用除正常數字之外的其他內容來顯示數字。
有了這樣的庫,給出了代碼:
#include <stdio.h> // Could legitimately include functions that aren't
// defined by the Standard, but which start with __.
int main(void)
{
__select_alternate_digits("⁰¹²³⁴⁵⁶⁷⁸⁹");
printf("%d",123);
__select_alternate_digits(0); // Reset to default set
}
對__select_alternate_digits
的調用可能導致上述程序輸出“123”而不是“123”。 如果編譯器捆綁了自己的printf
函數,它可能知道它的行為不會受到任何其他函數調用的影響。 但是,如果它使用外部庫,那么除非程序完全不需要編譯器一無所知的函數調用,否則質量編譯器應該假設這些函數可能具有編譯器無法預測的效果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.