簡體   English   中英

為什么address-of operator('&')可以與在C ++中使用寄存器存儲類說明符聲明的對象一起使用?

[英]Why address-of operator ('&') can be used with objects that are declared with the register storage class specifier in C++?

在C編程語言中,我們不允許將address-of運算符(&)與使用寄存器存儲類說明符聲明的變量一起使用。

它給出了error: address of register variable 'var_name' requested

但是,如果我們制作一個c ++程序並執行相同的任務(即使用& with寄存器存儲變量),它不會給我們任何錯誤。

例如。

#include <iostream>
using namespace std;
int main()
{
    register int a;
    int * ptr;
    a = 5;
    ptr = &a;
    cout << ptr << endl;
    return 0;
}

輸出: -

0x7ffcfed93624

那么這必須是C ++的一個額外功能,但問題在於C和C ++中寄存器類存儲的區別。

在C ++中故意刪除了取得地址的限制 - 它沒有任何好處,它使語言更復雜。 (例如,如果綁定對register變量的引用會發生什么?)

register關鍵字多年來沒有多大用處 - 編譯器非常擅長確定自己放入寄存器的內容。 實際上,在C ++中,該關鍵字目前已被棄用,最終將被刪除。

register存儲類最初向編譯器暗示如此頻繁地使用變量如此合格,以至於將其值保留在存儲器中將是性能缺陷。 絕大多數 CPU架構(可能不是SPARC?甚至不確定是否存在反例)如果沒有先將一個或兩個從內存加載到其寄存器中,就無法在兩個變量之間執行任何操作。 將變量從存儲器加載到寄存器中並在操作后將它們寫回存儲器所需的CPU周期比操作本身多出許多倍。 因此,如果頻繁使用變量,則可以通過為其預留寄存器而不打擾存儲器來實現性能增益。

但是,這樣做有各種各樣的要求。 每種CPU架構都有許多不同之處:

  • 所有處理器都有固定數量的寄存器,但每個處理器型號都有不同的編號。 在80年代,你可能有4個可以合理地用於register變量。
  • 大多數處理器不支持每個指令使用每個寄存器。 在80年代,只有一個可用於加法和減法的寄存器並不常見,你可能無法使用相同的寄存器作為指針。
  • 調用約定規定了不同的寄存器集,這些寄存器可能被子程序(即函數調用)覆蓋。
  • 寄存器的大小因處理器而異,因此存在register變量不適合寄存器的情況。

由於C旨在獨立於平台,因此標准無法強制執行這些限制。 換句話說,雖然對於只有4個機器寄存器的系統來說,編譯一個帶有20個register變量的過程是不可能的,但是C程序本身不應該是“錯誤的”,因為沒有邏輯上的原因機器不能有20個寄存器。 因此, register存儲類始終只是一個提示 ,如果特定目標平台不支持它,編譯器可以忽略它。

無法引用寄存器是不同的。 register 具體不在存儲器中保持更新,如果對存儲器進行了更改,則不保持當前狀態; 這就是存儲類的重點。 由於它們不打算在內存中具有保證的表示,因此它們在邏輯上不能在內存中具有對可能獲得指針的外部代碼有意義的地址。 寄存器沒有自己CPU的地址,並且它們幾乎從不具有任何協處理器可訪問的地址。 因此,任何獲取對register的引用的嘗試總是錯誤的。 C標准可以輕松地執行這一規則。

然而,隨着計算的發展,一些趨勢的發展削弱了register存儲類本身的目的:

  • 處理器帶來了更多的寄存器。 今天你可能至少有16個,它們可能在大多數情況下可以互換使用。
  • 多核處理器和分布式代碼執行已經變得非常普遍; 只有一個核心可以訪問任何一個寄存器,並且它們永遠不會共享而不涉及內存。
  • 將寄存器分配給變量的算法變得非常有效。

實際上,編譯器現在非常善於將變量分配給寄存器,它們通常在優化方面比任何人都做得更好。 他們當然知道你最常使用哪些,而不告訴他們。 如果編譯器需要遵守手動register提示,那么編譯器 (即不適用於標准或程序員)會產生這些優化會更復雜。 編譯器斷然忽略它們變得越來越普遍。 到C ++存在時,它已經過時了。 它包含在標准中以便向后兼容,以使C ++盡可能接近C的正確超集。編譯器遵守提示的要求以及因此強制執行提示可以遵守的條件的要求被削弱了因此。 今天,存儲類本身已被棄用。

因此,即使現在仍然如此(並且直到計算機甚至沒有寄存器)你無法邏輯地引用CPU寄存器, register 存儲類將被尊重的期望已經過時了標准要求編譯器要求您在使用它時合乎邏輯是不合理的。

引用的寄存器將是寄存器本身。 如果調用函數將ESI作為引用參數傳遞,則被調用函數將使用ESI作為參數。 正如Alan Stokes所指出的,問題是如果另一個函數也調用相同的函數,但這次使用EDI作為相同的引用參數。

為了使其工作,需要創建兩個重載的被調用函數實例,一個以ESI作為參數,一個以EDI作為參數。 我不知道是否有任何實際的C ++編譯器實際上實際上實現了這樣的優化,但這就是如何做到的。

通過引用注冊的一個示例是std :: swap()被優化的方式(兩個參數都是引用),這通常最終成為內聯代碼。 有時沒有交換發生:例如,std :: swap(a,b),沒有發生交換,而是在后面的代碼中交換a和b的意義(引用對b和副的引用是什么反之亦然)。

否則,引用參數將強制變量位於內存而不是寄存器中。

暫無
暫無

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

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