簡體   English   中英

C編譯器如何持續優化無法訪問的代碼?

[英]How consistently C compilers optimize unreachable code?

假設您擁有(出於此處不重要的原因)以下代碼:

 int k = 0;
 ...  /* no change to k can happen here */
 if (k) { 
   do_something();
 }

使用-O2標志,GCC不會識別任何代碼,因為if測試始終為假。

我想知道這是否在編譯器中是非常普遍的行為,還是我不應該依賴的東西。

有人知道嗎

跨編譯器沒有非常普遍的行為。 但是,有一種方法可以探索不同的編譯器如何處理特定的代碼部分。 編譯器資源管理器將幫助您回答有關代碼生成的每個問題,但是您當然必須熟悉匯編語言。

在這種情況下,消除死代碼對於任何現代的優化編譯器都是微不足道的。 我肯定會依靠它,因為已經啟用了優化功能,並且您完全可以確定編譯器可以在檢查時證明該值為零。

但是,您應該意識到,有時您的代碼具有比您想象的更多的潛在副作用。


問題的第一個來源是調用非內聯函數。 每當您調用未內聯的函數時(即因為其定義位於另一個轉換單元中),編譯器就會假定所有全局變量和堆的整個內容在此調用內都可能更改。 局部變量是幸運的例外,因為編譯器知道間接修改它們是非法的……除非您將局部變量的地址保存在某個地方。 例如,在這種情況下, 無法消除無效代碼:

int function_with_unpredictable_side_effects(const int &x);
void doit() {
  int k = 0;
  function_with_unpredictable_side_effects(k);
  if (k)
    printf("Never reached\n");
}

因此,編譯器必須做一些工作,甚至對於局部變量也可能會失敗。 順便說一下,我相信在這種情況下解決的問題稱為逃逸分析


問題的第二個來源是指針別名 :編譯器必須考慮到代碼中的各種指針和引用可能是相等的,因此通過一個指針更改某些內容可能會更改另一個指針的內容。 這是一個例子:

struct MyArray {
  int num;
  int arr[100];
};
void doit(int idx) {
  MyArray x;
  x.num = 0;
  x.arr[idx] = 7;
  if (x.num)
    printf("Never reached\n");
}

Visual C ++編譯器不會消除無效代碼 ,因為它認為您可以將x.num作為x.arr[-1]訪問。 對您來說,這聽起來似乎很糟糕,但是此編譯器已在gamedev領域中使用了很多年,並且此類hack並不少見,因此編譯器始終處於安全狀態。 另一方面,GCC會刪除無效代碼。 可能與它對嚴格的指針別名規則的利用有關。


PS const鍵工作從未被優化程序使用,僅以C / C ++語言提供,以方便程序員使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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