2013-05-20 122 views
11

如果我的代碼中有某處使用變量的地址(例如將它傳遞給其他函數),編譯器會自動選擇將它存儲在內存中? (而不是將其存儲在寄存器中的可能性)。存儲在寄存器中的變量的地址

否則,如果我要求這樣的變量的地址(存儲爲寄存器)會發生什麼?我知道我們不能將顯式設置的變量地址註冊(register int c)。

編輯

例如,如果我這樣做

int c = 1; 
print("Address of c: %p", &c); 

那麼這個變量不能被存儲在寄存器中,可能嗎?編譯器會自動將它設置爲存儲在內存中?否則(如果它只存儲在一個寄存器中),屏幕上顯示的地址是什麼?

+0

我不清楚你問的是什麼。如果你正在討論函數參數,那麼它們都是通過堆棧來處理的。 – alex

+3

一些調用約定使用堆棧,其他人使用寄存器或兩者的組合。它們並不都是由堆棧處理的,除非你正在討論特定的具有特定編譯器的架構上的特定調用約定。 –

+0

我的意思是在一般意義上使用變量的地址。例如,我可以將地址打印到屏幕上。 –

回答

19

首先,C標準禁止採用宣佈爲register的變量的地址,就像它對struct中的位字段所做的那樣。

對於非註冊(「自動」)變量,簡短答案是肯定的。優化器的最簡單的策略是立即泄漏地址的變量。

「溢出」只是寄存器分配文獻中的一個術語,意思是「決定放在內存中而不是寄存器」。

一個複雜的優化器可以做一個別名分析並且仍然在寄存器中保存一個值,即使它的地址已被佔用。這是可能的,無論哪裏可以證明所產生的指針不可能被用來改變值。

另一個相關優化是生存分段。這允許一個變量被存儲在一個寄存器中,用於保存一個有用值(它的「活動範圍」)並在其他部分溢出的指令範圍的一部分。在這種情況下,溢出的部分將對應於指針可能使用來更改變量值的位置。例如:

x = 3; 
... lots of computations involving x 
if T { 
    // SPILL HERE, so store register holding x to memory 
    int *p = &x; 
    ... lots of computations, perhaps using p to change x 
    *p = 2; 
    // DONE SPILL HERE, so reload register 
    ... more code here not using p to change x. 
} 
else { 
    ... lots of computations involving x. 
} 

此代碼的分配對於x的堆疊位置,但它加載到寄存器中的代碼的頂部,將其保持有除區域標記爲SPILL的侵略性優化器。該區域將被寄存器存儲器和匹配的寄存器負載所包圍。

+0

對不起,我在第一段沒有真正的第一句話。優化器(編譯器)溢出了這些變量? –

+1

「溢出」僅僅意味着寄存器分配器決定將一個變量放入內存而不是寄存器中。溢出可能會發生許多原因。也許最常見的是變量比寄存器更多,所以一些變量必須「溢出」可用的寄存器池。 – Gene

3

通過獲取其地址,可以強制編譯器將該變量放入內存中,而不是將其優化爲寄存器。

這個答案有一些好的信息:Address of register variable

+4

這不是準確的。我編譯了'int foo(int x){int y = x,* z =&y;返回* z * * z; }'使用'cc -O3 -std = c99 -S'的Apple clang版本4.0,並檢查生成的彙編代碼。它在任何時候都沒有在內存中放入'x'或'y'。如果編譯器不能確定所需的「可觀察」行爲不能以其他方式提供,那麼編譯器只會強制將該值放入內存中。 –

0

編譯器必須非常小心優化指針,因爲任何人都可以改變它們在幕後。這就是爲什麼優化關鍵字如restrict的原因(告訴編譯器在任何地方都沒有其他指針副本)。所以一般你不會有你描述的情況。