2011-06-02 73 views

回答

3

相當多的時間,是的。它通常被稱爲鏈接器剝離。

-2

這一切都取決於編譯器及其設置(內置「調試」配置的代碼通常未優化),以及代碼本身和行星對齊。

潛在的問題是:你不應該擔心那些東西。相信你的編譯器。

+2

如果您有一些外部要求,即可執行文件包含某個未使用的符號,則必須擔心。沒有得到解決。 – 2011-06-23 14:01:40

+0

@Tomalak我同意,有時知道你的編譯器輸出是必要的。但對大多數情況來說,這並不重要。 – 2011-06-23 14:03:36

+2

當然。另一方面,瞭解您的工具以及如何正確使用它們。 – 2011-06-23 14:06:32

2

說到MS,它是鏈接器,它在鏈接階段處理此問題,並且編譯器可能會警告您未使用的靜態函數(文件範圍)。如果您希望鏈接器刪除未使用的函數,請使用/OPT:REF選項:

4

使用gcc如果啓用優化,它可以刪除未使用的函數和死代碼。

更多關於GCC的優化,可以發現here

5

許多編譯器做的,但是這取決於具體的實施。調試版本通常會包含所有功能,以便在調試器中調用或檢查它們。由於我不完全瞭解(*)的原因,許多嵌入式系統編譯器將包含對象文件中的所有功能(如果它們包含任何功能),但會完全省略完全不使用的任何對象文件。

請注意,在支持Reflection的語言(例如Java,C#,vb.net等)中,給定一個函數的名字,可以在運行時創建對它的引用,即使代碼中沒有引用。例如,一個例程可以接受來自控制檯的字符串,以某種方式使用該字符串,並以該名稱生成對函數的調用。編譯器或鏈接器無法知道可能會如此生成哪些名稱,因此無法知道可以安全地從代碼中省略哪些函數。但是,在C或C++中不存在這樣的困難,因爲沒有定義的方法讓代碼創建對函數,變量或常量的引用,而不在代碼中存在明確的引用。有些實現可能會安排一些事情,以便連續聲明的常量或變量將被連續存儲,因此可以通過向先前聲明的一個偏移量添加偏移量來創建對後面聲明的引用的引用,但這些技巧的行爲是明確的不受C或C++標準的保證。 (*)我知道它使得編譯和鏈接變得更加容易,但是今天的計算機應該沒有運行更復雜的編譯和鏈接算法的麻煩,而這種算法比過去幾十年來的實踐要容易。如果沒有別的,預編譯/鏈接階段可以使用兩步預編譯/預鏈接/編譯/鏈接方法生成所使用的事物列表,然後在「真實」編譯/鏈接階段省略那些不是。

+0

雖然我猜想一些令人頭疼的內聯程序集可能會調用一個本來可以安全使用的函數從代碼中省略? – Andy 2017-07-06 23:27:07

+0

@Andy;一般來說,只有當它使用有關函數的地址時。 – supercat 2017-07-07 05:43:28

15

如果使用/Gy進行編譯並鏈接到/OPT:REF,MSVC(Visual Studio編譯器/鏈接器)可以執行此操作。

如果您使用-ffunction-sections -fdata-sections進行編譯並鏈接到--gc-sections,GCC/binutils可以執行此操作。

不知道其他編譯器。

+0

請注意,'/ OPT:REF'會導致非標準行爲:它將優化僅取得地址的函數,以使地址變爲無效。 GCC不會發生這種情況。 – rubenvb 2016-08-10 05:29:38

12

一般來說,答案是:

是:未使用static功能。

編號:  未使用的全局可用函數。

編譯器不知道其他編譯單元是否引用它。而且,大多數對象模塊類型不允許在編譯後刪除函數,也不提供鏈接器判斷是否存在內部引用的方法。 (鏈接器可以分辨出是否有外部。)有些鏈接器可以做到這一點,但很多事情都可以解決這個問題。

當然,它自己的模塊中的函數不會被任何鏈接器不必要地加載,除非它是共享庫的一部分。 (因爲它在將來可能會在運行時被引用,很明顯。)