2016-12-19 85 views
4

當涉及到C和C++語言時,編譯器是否會優化對常量變量的引用,以便程序自動知道要引用的值,而不必查看常量變量的內存位置?說到數組,是否依賴於在編譯時指向數組的索引值是否爲常量?編譯器是否優化對常量變量的引用?

例如,看看下面的代碼:

int main(void) { 
    1: char tesst[3] = {'1', '3', '7'}; 
    2: char erm = tesst[1]; 
} 

該編譯器「變」 2號線到「字符ERM =‘3’」在編譯時?

+10

它可能也可能不會 - 取決於編譯器,它的版本,優化級別,所涉及代碼的複雜性等。檢查編譯器爲您的目標平臺生成的程序集。 –

+1

gcc6.2可以根據需要優化-O1或更高版本:https://godbolt.org/g/yFLoYo – 0x5453

+0

您可以通過反彙編程序並查看反彙編的優化代碼,輕鬆地自己回答這些問題。例如Codeblocks IDE - > Debugger窗口 - >反彙編。您不必成爲x86彙編程序的專家就可以基於此理解粗略的想法。 – Lundin

回答

7

它主要取決於優化水平和你正在使用的編譯器。

通過最大限度的優化,編譯器確實可能只是用char erm = '3';替換整個代碼。無論如何,GCC -O3都會這樣做。

但是當然這取決於你對這個變量做了什麼。編譯器甚至可能不會分配變量,而只是在變量發生的操作中使用原始數字。

3

取決於編譯器版本,使用的優化選項和許多其他事情。如果你想確保const變量被優化,並且它們是編譯時間常量,你可以在C++中使用類似constexpr的東西。它保證在編譯時進行評估,而不像常規的const變量。

編輯:可以在編譯時或運行時評估constexpr。爲了保證編譯時評估,我們必須在需要常量表達式的地方使用它(例如,作爲數組綁定或作爲案例標籤),或者使用它來初始化constexpr。所以在這種情況下

constexpr char tesst[3] = {'1','3','7'}; 
constexpr char erm = tesst[1]; 

會導致編譯時評估。尼斯閱讀https://isocpp.org/blog/2013/01/when-does-a-constexpr-function-get-evaluated-at-compile-time-stackoverflow

+0

如果我有一個整型變量i,其值由執行時決定用戶輸入,然後調用tesst [i]。程序是否可以爲此進行優化? –

+1

「constexpr」表達式不保證在編譯時進行評估。如果程序格式良好,那麼在編譯時總是可以*評估一個'constexpr',但是編譯器本身沒有義務執行該評估。 (然而,使用這種表達的上下文可能會產生這樣的義務。) –

+0

@MånsNilsson顯然,編譯器無法預測用戶將輸入什麼內容。但它可以預測,你只能使用陣列的3個字節中的1個,並擺脫不使用的字節。 – Lundin

9

我個人認爲發佈的代碼會變成「無」,因爲這兩個變量實際上都沒有使用,因此可以刪除。

但是,現代編譯器(gcc,clang,msvc等)應該能夠將該引用替換爲它的常量值[只要編譯器可以合理確定tesst的內容不是被改變 - 如果你將tesst傳遞給一個函數,即使它作爲const引用,並且編譯器實際上並不知道該函數不會改變它,它會假定它會加載該值。

編譯這個使用clang -O1 opts.c -S

#include <stdio.h> 

int main() 
{ 
    char tesst[3] = {'1', '3', '7'}; 
    char erm = tesst[1]; 

    printf("%d\n", erm); 
} 

生產:

... 

main: 
    pushq %rax 
.Ltmp0: 
    movl $.L.str, %edi 
    movl $51, %esi 
    xorl %eax, %eax 
    callq printf 
    xorl %eax, %eax 
    popq %rcx 
    retq 

... 

所以,同爲printf("%d\n", '3');

[我用C而不是C++,因爲這將是約50,如果我用cout彙編的線條,一切都被內聯]

我希望gcc和MSVC作出類似的優化(測試gcc -O1 -S和它由一些符號名略有不同)

,並說明,「如果你調用一個函數它可能不會做」給完全相同的代碼,除了:

#include <stdio.h> 

extern void blah(const char* x); 

int main() 
{ 
    char tesst[3] = {'1', '3', '7'}; 
    blah(tesst); 
    char erm = tesst[1]; 

    printf("%d\n", erm); 
} 


main:         # @main 
    pushq %rax 
    movb $55, 6(%rsp) 
    movw $13105, 4(%rsp)   # imm = 0x3331 
    leaq 4(%rsp), %rdi 
    callq blah 
    movsbl 5(%rsp), %esi 
    movl $.L.str, %edi 
    xorl %eax, %eax 
    callq printf 
    xorl %eax, %eax 
    popq %rcx 
    retq 

現在,它獲取的價值從內部 tesst

相關問題