[英]Compiler changes printf to puts
考慮以下代碼:
#include <stdio.h>
void foo() {
printf("Hello world\n");
}
void bar() {
printf("Hello world");
}
這兩個函數產生的程序集是:
.LC0:
.string "Hello world"
foo():
mov edi, OFFSET FLAT:.LC0
jmp puts
bar():
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
現在我知道puts 和 printf之間的區別,但我發現 gcc 能夠內省 const char* 並確定是調用 printf 還是 puts 非常有趣。
另一個有趣的事情是,在bar
,編譯器將返回寄存器 ( eax
) 清零,即使它是一個void
函數。 為什么它在那里而不是在foo
這樣做?
我假設編譯器“內省了我的字符串”是否正確,或者對此有另一種解釋?
我假設編譯器“內省了我的字符串”是否正確,或者對此有另一種解釋?
是的,這正是發生的事情。 這是由編譯器完成的非常簡單且常見的優化。
由於您的第一個printf()
調用只是:
printf("Hello world\n");
它相當於:
puts("Hello world");
由於puts()
不需要掃描和解析字符串以獲取格式說明符,因此它比printf()
快得多。 編譯器注意到您的字符串以換行符結尾並且不包含格式說明符,因此會自動轉換調用。
這也節省了一點空間,因為現在只需要在生成的二進制文件中存儲一個字符串"Hello world"
。
請注意,對於以下形式的調用,這通常是不可能的:
printf(some_var);
如果some_var
不是簡單的常量字符串,則編譯器無法知道它是否以\\n
結尾。
其他常見的優化有:
strlen("constant string")
可能會在編譯時被評估並轉換為數字。location1
和location2
不重疊memmove(location1, location2, sz)
可能會轉換為memcpy()
。memcpy()
可以在單個mov
指令中轉換,即使尺寸更大,有時也可以內聯調用以更快。另一個有趣的事情是,在
bar
,編譯器將返回寄存器 (eax
) 清零,即使它是一個void
函數。 為什么它在那里而不是在foo
這樣做?
請參閱此處: 為什么 %eax 在調用 printf 之前歸零?
另一個有趣的事情是,在 bar 中,編譯器將返回寄存器 (eax) 清零,即使它是一個 void 函數。 為什么它在那里而不是在 foo 中這樣做?
這與標題中的問題完全無關,但仍然很有趣。
異或歸零%eax
在調用 printf之前,因此是調用的一部分,與返回值無關。 發生這種情況的原因是printf
是一個可變參數函數,並且可變參數函數的 x86_64 ABI 需要在 xmm 寄存器中傳遞浮點參數,並且需要在 %al 中傳遞此類參數的數量。 所以這條指令是為了確保 %al 為 0,因為沒有參數在 xmm 寄存器中傳遞給 printf。
puts 不是可變參數函數,因此不需要它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.