當涉及到C和C++語言時,編譯器是否會優化對常量變量的引用,以便程序自動知道要引用的值,而不必查看常量變量的內存位置?說到數組,是否依賴於在編譯時指向數組的索引值是否爲常量?編譯器是否優化對常量變量的引用?
例如,看看下面的代碼:
int main(void) {
1: char tesst[3] = {'1', '3', '7'};
2: char erm = tesst[1];
}
該編譯器「變」 2號線到「字符ERM =‘3’」在編譯時?
當涉及到C和C++語言時,編譯器是否會優化對常量變量的引用,以便程序自動知道要引用的值,而不必查看常量變量的內存位置?說到數組,是否依賴於在編譯時指向數組的索引值是否爲常量?編譯器是否優化對常量變量的引用?
例如,看看下面的代碼:
int main(void) {
1: char tesst[3] = {'1', '3', '7'};
2: char erm = tesst[1];
}
該編譯器「變」 2號線到「字符ERM =‘3’」在編譯時?
它主要取決於優化水平和你正在使用的編譯器。
通過最大限度的優化,編譯器確實可能只是用char erm = '3';
替換整個代碼。無論如何,GCC -O3都會這樣做。
但是當然這取決於你對這個變量做了什麼。編譯器甚至可能不會分配變量,而只是在變量發生的操作中使用原始數字。
取決於編譯器版本,使用的優化選項和許多其他事情。如果你想確保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
如果我有一個整型變量i,其值由執行時決定用戶輸入,然後調用tesst [i]。程序是否可以爲此進行優化? –
「constexpr」表達式不保證在編譯時進行評估。如果程序格式良好,那麼在編譯時總是可以*評估一個'constexpr',但是編譯器本身沒有義務執行該評估。 (然而,使用這種表達的上下文可能會產生這樣的義務。) –
@MånsNilsson顯然,編譯器無法預測用戶將輸入什麼內容。但它可以預測,你只能使用陣列的3個字節中的1個,並擺脫不使用的字節。 – Lundin
我個人認爲發佈的代碼會變成「無」,因爲這兩個變量實際上都沒有使用,因此可以刪除。
但是,現代編譯器(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
。
它可能也可能不會 - 取決於編譯器,它的版本,優化級別,所涉及代碼的複雜性等。檢查編譯器爲您的目標平臺生成的程序集。 –
gcc6.2可以根據需要優化-O1或更高版本:https://godbolt.org/g/yFLoYo – 0x5453
您可以通過反彙編程序並查看反彙編的優化代碼,輕鬆地自己回答這些問題。例如Codeblocks IDE - > Debugger窗口 - >反彙編。您不必成爲x86彙編程序的專家就可以基於此理解粗略的想法。 – Lundin