簡體   English   中英

編譯器將 printf 更改為 puts

[英]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")可能會在編譯時被評估並轉換為數字。
  • 如果編譯器確定location1location2不重疊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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM