簡體   English   中英

這么有限的寄存器,怎么會有這么多的寄存器變量呢?

[英]How can there be so many register variables, with such a limited number of registers?

我在玩 C 時,我意識到,如果我聲明了一堆寄存器變量,這些值不會被覆蓋嗎? 從我從組裝中可以看出,微處理器中沒有大量寄存器,不足以滿足我創建的需求。 C 如何保留所有值?

沒有要求所有用register聲明的變量都必須保存在 CPU 寄存器中。

這是 C 標准所說的:

具有存儲類說明符寄存器的對象的標識符聲明建議對對象的訪問盡可能快。 這些建議的有效程度是由實施定義的。

參考:ISO C11 N1570 草案,6.7.1 第 6 段。請注意,它甚至沒有提到 CPU 寄存器。

符合標准的編譯器可以簡單地忽略所有register關鍵字(除了對獲取register對象的地址施加一些限制)。

實際上,大多數編譯器只會在 CPU 寄存器中放置盡可能多的register變量。

事實上,現代優化編譯器可能比大多數程序員更擅長寄存器分配——特別是因為他們可以在每次修改程序后重新編譯程序時重新計算寄存器映射。

現在的普遍觀點是register關鍵字沒有提供太多好處。

舊編譯器會分配盡可能多的寄存器來register變量(在某些情況下,這個數字是 0)並在堆棧上分配剩余的變量。

現代編譯器通常會忽略register關鍵字。 他們使用復雜的寄存器分配器,自動將盡可能多的變量保存在寄存器中。

您可以依賴的register的唯一效果是,如果您嘗試獲取寄存器變量的地址,則會收到一條診斷消息。 否則,寄存器變量的行為就像自動變量一樣。

register提示編譯器可以將變量保存在寄存器中。 您不能強制編譯器使用比目標體系結構上存在的寄存器更多的寄存器,原因很明顯,這是不可能的。


在 C 中, register關鍵字僅表示無法獲取變量的地址。 這會阻止你做任何會阻止編譯器將它保存在寄存器中的事情,但不需要它在寄存器中。

來自https://en.cppreference.com/w/c/language/storage_duration

寄存器說明符只允許用於在塊范圍內聲明的對象,包括函數參數列表。 它指示自動存儲持續時間和無鏈接(這是這些類型的聲明的默認值),但另外提示優化器如果可能的話將該變量的值存儲在 CPU 寄存器中。 不管這種優化是否發生,聲明為 register 的變量不能用作地址運算符的參數,不能使用 alignas (C11 起),並且寄存器數組不能轉換為指針。

多年來它並沒有真正做任何事情:優化編譯器已經盡可能將變量保存在 regs 中。 對於全局變量或已獲取其地址的變量,則可能僅用於函數的一部分,如果無法優化變量,則將結果存儲回內存。


順便說一句, register在 C++ 中被正式棄用,而 C++17 實際上從語言中刪除了它。 https://en.cppreference.com/w/cpp/language/storage_duration


相關:GNU C 有register int foo asm("eax"); (或任何其他寄存器),但即使這樣也只能保證在用作局部變量時內聯匯編語句的操作數時有效。 在當前的 GCC 版本中,它確實會導致編譯器將該寄存器用於變量,除非它需要跨函數調用或其他任何方式將其溢出/重新加載到堆棧內存。

https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html

但是在 GNU C 中,您可以使用全局寄存器變量,其中一個寄存器在程序的整個生命周期內專用於全局,這會損害未使用該變量的代碼的優化。 這是一個有趣的選項,但不是您應該使用的選項。

C 旨在允許編譯器在解析函數時為其生成匯編代碼,而不必讀取整個函數、檢查它,然后再生成代碼。 已解析程序的編譯器:

int test(void)
{
  int x=0,y=0;
  int *p = &y;

  while(x < 10)
  {
    x++;
    foo();
    x++;
    *p *= 3;
    x++;
    bar();
    ...

無法知道是否值的方式x可以被安全地保存在寄存器跨越調用foo和/或在操作*p ,或者是否有可能為foo改變的值x

register關鍵字的目的是有效地告訴編譯器,將對象的值跨函數調用或寫入指針的操作保存在寄存器中是安全的,即使它沒有看到代碼可能使用的所有內容目的。 如果將對象的地址傳遞給嵌套函數不違反約束,那么即使在今天這種含義也很有用,但是允許編譯器假設在使用命名對象左值的任何上下文中,所有操作都將涉及該命名對象左值- 對象左值。 如果一個對象的地址從未被采用,則不需要限定符來引起這樣的假設,但在對象的地址采用但沒有在涉及該對象的沖突操作中持久化的情況下,這樣的限定符可以提供編譯器信息,否則它不會有。

變量通常存儲在堆棧中。 也就是一塊內存。 變量的值通常加載到寄存器中進行操作,如果要操作另一個變量,則將其移回堆棧(保存)。 通常,變量甚至不會加載到寄存器中,而是在堆棧上進行操作。

暫無
暫無

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

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