2013-10-21 59 views
8

我這裏有一個樣本文件:爲什麼在編譯和鏈接C代碼時-lm在某些情況下不是必需的?

#include <stdio.h> 
#include <math.h> 

int main(){ 
    printf("%f\n", log(10)); 
} 

當我與gcc sample.c -o a編譯它工作得很好。我可以用./a來運行它,它會像預期的那樣生成輸出2.302585

然而,當我的文件看起來像這樣:

#include <stdio.h> 
#include <math.h> 

int main(){ 
    double a = 10; 
    printf("%f\n", log(a)); 
} 

它不gcc sample.c -o a編譯。相反,我必須使用gcc sample.c -o a -lm,這樣我才能明顯地告訴它「連接數學」......這就是我沒有真正遵循的地方,爲什麼我不必在第一個示例中將數學關聯起來呢?究竟什麼是「連接數學」呢?我已經和C編譯器合作過了一段時間,所以如果這是一個很差的問題,請原諒我。

回答

6

檢查反彙編,您可能會發現編譯器在第一種情況下完全優化了對log()的調用(因此沒有任何關聯),但不會在第二種情況下調用。在這種特殊情況下,glibc的定義:

# define M_LN10  2.30258509299404568402 
math.h

,例如,任何標準庫函數可以被實現爲宏,因此它可以計算出其中的一些東西沒有一個函數調用。

2

由於某些原因,即使使用-O0,gcc也優化了log(const)。所以在第一種情況下沒有log()調用。檢查裝配驗證:

的gcc sample.c文件-S

鐺,例如不優化出來的O0。 但在O2 gcc優化了這兩種情況下的呼叫。

5

根據GCC document,可能不會調用數學庫函數,因此定義了一些內聯函數,並且可能會在某些情況下調用該函數。

... GNU C庫爲許多常用的數學函數提供優化。當使用GNU CC並且用戶激活優化器時,定義了幾個新的內聯函數和宏。這些新函數和宏與庫函數具有相同的名稱,因此用於替代後者。在內聯函數的情況下,編譯器將決定使用它們是否合理,並且這個決定通常是正確的。

這意味着不需要調用庫函數可能需要,並且可以顯着提高生成代碼的速度。缺點是代碼大小會增加,並且增加並不總是可以忽略不計。

相關問題