一邊念叨例外處理和編譯器標志部分-fno-exceptions在GCC手冊中,我遇到了下面幾行:
例外處理開銷可以用可執行二進制檔案的大小來衡量,并隨著底層作業系統的能力和 C 編譯器的特定配置而變化。在具有同齡 GNU 系統軟體的最新硬體上,啟用例外處理的組合代碼和資料大小開銷約為 7%。
我試圖通過使用帶有和不帶有-fno-exceptions標志的Ubuntu 20.04 和 gcc 10.3.0 編譯一些簡單的 C 程式(無一例外地拋出代碼)來重現這種開銷,但是在編譯的二進制可執行檔案的大小方面沒有觀察到任何差異。
所以,我得出的結論是從手冊中參考的句子僅僅是指以被重新編譯使用的libstdc 檔案時產生的二進制檔案-fno-exceptions,因為在這種情況下,每一次出現try,catch并且throw將被替換if...else分支。
我對此并不完全確定,所以這里是我的問題:
a)用戶代碼被編譯-fno-exceptions使用關鍵字只能預防try,catch并throw與自身并不產生較小的二進制檔案,對不對?
b) 被編譯的用戶代碼-fno-exceptions仍然可能暴露于從 libstdc 函式拋出的例外,如果這些沒有被(重新)編譯-fno-exceptions,對嗎?
c) 使用-fexceptions(默認)編譯的用戶代碼確實會產生更大的二進制檔案,因為生成的幀展開資訊,但只有在實際使用例外時,對嗎?
uj5u.com熱心網友回復:
它可以減少二進制檔案的大小,并且通常用于較大的程式。但是,不能保證總是這樣做。
a) 使用 -fno-exceptions 編譯的用戶代碼只會阻止使用關鍵字 try、catch 和 throw 并且不會自行生成較小的二進制檔案,對嗎?
不,它肯定會對代碼生成產生影響。但是,例外不會不加選擇地增加代碼大小。要生成的幀展開代碼必須存在可能涉及的例外。在展開期間還必須有一些事情要做(即非平凡的解構式)。如果給定函式中不存在一個或另一個,則-fno-exceptions不會對該函式產生影響。
例如,編譯以下將清楚地顯示使用-fno-exceptions.
#include <vector>
void foo(); // could potentially throw.
void bar() {
std::vector<int> v(12); // has non-trivial destructor.
foo();
}
在Godbolt上看到
請注意以下每個更改如何消除例外處理代碼:
- 將 的宣告更改
foo()為void foo() noexcept;。 foo()在同一個 TU 中提供非拋出實作:void foo() {}- 將向量的構造移動到 after
foo()被呼叫。
b) 使用 -fno-exceptions 編譯的用戶代碼仍然可能暴露于從 libstdc 函式拋出的例外,如果這些代碼尚未使用 -fno-exceptions 進行(重新)編譯,對嗎?
libstdc 拋出的任何例外冒泡到編譯的代碼中-fno-exceptions都將導致程式立即終止。如果這算作“暴露”給你,那么是的。
但是,請記住,libstdc 的很大一部分是直接在頭檔案中實作的,并且您的編譯器標志將應用于庫的那部分。
c) 使用 -fexceptions(默認值)編譯的用戶代碼確實會因為生成的幀展開資訊而產生更大的二進制檔案,但只有在實際使用例外時,對嗎?
關閉但不完全。代碼將在任何可能引發例外的地方發出。這包括對未noexcept在與正在編譯的 TU 不同的 TU 中定義的函式的任何呼叫。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/328256.html
下一篇:Netbeans:意外例外
