for(int i=0;i<10;i++)
{
int x=0;
printf("%d",x);
{
int x=10;
printf("%d",x);
}
printf("%d",x);
}
這裏我想知道變量x的內存將被分配兩次還是僅僅在退出第二個塊並且內存被分配一次(對於x)後才重置的值?變量的塊結構內存分配
for(int i=0;i<10;i++)
{
int x=0;
printf("%d",x);
{
int x=10;
printf("%d",x);
}
printf("%d",x);
}
這裏我想知道變量x的內存將被分配兩次還是僅僅在退出第二個塊並且內存被分配一次(對於x)後才重置的值?變量的塊結構內存分配
從視圖C編程模型的點,的x
兩個定義是兩個完全不同的對象。內部塊中的賦值不會影響外部塊中的x
的值。
此外,循環的每次迭代的定義也計算爲不同的對象。在一次迭代中將值分配給x
將不會影響後續迭代中的x
。
就實際實現而言,假設沒有進行優化,有兩種常見的情況。如果你打開了優化,你的代碼很可能會被丟棄,因爲編譯器很容易找出除了i
之外的循環對其他任何東西都沒有影響。
兩個常見的情況是
變量存儲在堆棧中。在這種情況下,編譯器將在外部x
的堆棧上預留一個插槽,並在內部x
的堆棧上預留一個插槽。理論上它應該在範圍的開始處分配槽並在範圍的末尾釋放槽,但這只是浪費時間,所以它會在每次迭代中重新使用槽。
變量存儲在寄存器中。這是現代64位體系結構更可能的選擇。同樣,編譯器應該在範圍的開始處「分配」(分配不是真正的合適的單詞)寄存器,並在結束時「釋放」,但它只會在現實生活中重複使用相同的寄存器。
在這兩種情況下,你會注意到,因爲編譯器使用相同的存儲空間,從每個迭代的值將被保留到下一次迭代。但是,如果你編譯並運行上述(與沒有優化),你可能會發現它打印合理的值,但是,每次你去一輪循環的時間從來沒有做到這一點
for (int i = 0 ; i < 10 ; ++i)
{
int x;
if (i > 0)
{
printf("Before %d\n", x); // UNDEFINED BEHAVIOUR
}
x = i;
printf("After %d\n", x);
}
,x
在理論上是一個全新的對象,所以第一個printf
訪問一個未初始化的變量。這是未定義的行爲,所以程序可能給你的價值從以前的迭代,因爲它使用相同的存儲或它可能 firebomb你的房子和賣你的女兒成奴隸制。
這是一個實現特定的細節。
例如,在代碼優化階段,它可能會檢測到那些未使用。所以不會爲他們分配空間。
即使某些編譯器沒有這個東西,那麼你可以預料到可能會出現兩個不同的變量空間未被分配的情況。
對於您的信息,事物大括號並不總是意味着它是不同的內存或堆棧空間。這是一個範圍問題。而對於變量,它可能是在CPU寄存器中分配的情況。
所以你不能說一般。你可以說的是他們的範圍不同。
因此,在堆棧中,變量x只被推送一次,當遇到第二個x時,我們只是改變這些值而不是再次推送它? – Zephyr
@Zephyr:你根本不知道......我的意思是,這是可能的,也可能是它被分配兩次。編譯器具體實現。編譯器不必生成代碼,以便在入口/出口範圍內的入口/出口處推送/彈出任何內容。 – coderredoc
C或C++編譯器會發生什麼情況? – Zephyr
我希望大多數編譯器都會使用堆棧中的內存來存儲這種類型的變量,如果任何內存都需要的話。在某些情況下,CPU寄存器可能用於一個或兩個x。兩者都有自己的存儲空間,但是與編譯器相關的是,該存儲的生命週期是否與源中聲明的變量範圍相同。因此,例如,用於「內部」x的內存可能會繼續在超出該變量超出範圍的地方使用 - 這實際上取決於編譯器的實現。
留出編譯器優化,可能會刪除這些未使用的變量,答案是兩次。
的x
口罩(技術術語)在其範圍內的其他定義如下其聲明第二個定義。 但是第一個定義在該範圍之後再次可見。 因此邏輯上(忘記優化)x
(x=0
)的第一個值必須在某個地方舉行,而x=10
「在場」。因此,兩件存儲(邏輯上)是必需的。
執行下面的C程序。典型部分輸出:
A0 x==0 0x7ffc1c47a868
B0 x==0 0x7ffc1c47a868
C0 x==10 0x7ffc1c47a86c
D0 x==0 0x7ffc1c47a868
A1 x==0 0x7ffc1c47a868
B1 x==0 0x7ffc1c47a868
C1 x==10 0x7ffc1c47a86c
//Etc...
通知僅點C如何看待變量x
具有值10,並與值0的變量是可見再次在點D也可參見如何的x
兩個版本都存儲在不同的地址。 從理論上講,每次迭代的地址可能不同,但我不知道實際執行的操作,因爲這是不必要的。但是,如果你做了這些非trival C++對象,它們的構造器和析構器會在每個循環中被調用,儘管它們仍然駐留在相同的地址處(實際上)。
人類讀者隱藏這樣的變量顯然令人困惑,不推薦。
#include <stdio.h>
int main(void) {
for(int i=0;i<10;i++)
{
int x=0;
printf("A%d x==%d %p\n",i,x,&x);
{
printf("B%d x==%d %p\n",i,x,&x);
int x=10;
printf("C%d x==%d %p\n",i,x,&x);
}
printf("D%d x==%d %p\n",i,x,&x);
}
}
感謝您的回答。但從邏輯上講,沒有必要分配堆棧內存兩次,因爲我們可以在範圍結束後更改變量的值,並將變量x的內存分配一次。我對嗎? – Zephyr
@ Zephyr:不,那是不對的。假設第一個賦值是(比如說)'int x = f();'其中'f()'是函數調用或者其他計算值。 (在編譯時未知)值是什麼時候被隱藏,比如說'int x = g();'(內部定義)。如果第二個範圍之後有第三個範圍 - 'int x = h();'可以與第二個範圍共享空間,但是在邏輯上我們需要兩個變量的空間。 – Persixty
@ Zephyr我已經修改了答案來顯示'x' - '&x'的地址。它們的兩個定義需要單獨存儲,程序大致相同,就好像第二個是'int y = 10'。唯一的區別是,在C語言中,在聲明之後,您不能在語法上引用內部塊中的外部版本。 – Persixty
如果機率很高,即使是一個內存,也可能不會分配內存。 –
內存分配兩次。在第2塊內,您可以通過「:: x」訪問第一個x更多 - https://en.wikipedia.org/wiki/Variable_shadowing – Macias
這些是2個不同的變量。保留2個值意味着2個「分配」 –