我不清楚在 C 中保證變數分配多長時間。
例如,如果我有:
void foo(void) {
int x;
int* y = &x;
...
}
堆疊上分配的空間是否x保證在整個持續時間內專門為此變數保留foo()?換句話說,y保證指向將在整個持續時間內保留的位置foo,或者編譯器是否可以決定由于x沒有被使用,堆疊空間可以用于其中的其他用途foo,因此*y可能會在不訪問y(或x)直接?
uj5u.com熱心網友回復:
當你問這樣的問題時,你應該清楚你是在問 C 語意還是關于程式實作。
C 語意是使用抽象計算機模型來描述的,其中所有操作都按照 C 標準描述的方式執行。當編譯器編譯一個程式時,它可以改變程式的實作方式,只要它得到相同的結果。(必須正確的結果是程式的可觀察行為:它的輸出,包括寫入檔案的資料、它的輸入/輸出互動以及它對易失性物件的訪問。)
在抽象計算機中,從執行開始到執行結束,x都保留了記憶體。1, 2foofoo
因此,在抽象計算機中,使用與否無關緊要x;為它保留記憶體,直到foo回傳或以其他方式結束它的執行(例如 alongjmp或程式終止)。
當編譯器實作這個程式時,它被允許x完全優化(如果它和它的地址沒有以任何需要保留記憶體的方式使用)或使用x它用于其他事情的相同記憶體,只要使用不會以改變可觀察行為的方式發生沖突。例如,如果我們有以下代碼:
int x;
int *y = &x;
x = 3;
printf("%d\n", x);
int b = 4;
printf("%d\n", b);
那么編譯器可能會使用與它相同的b記憶體x。
另一方面,如果我們有這個代碼:
int x;
int *y = x;
printf("%p\n", (void *) y);
int b = 4;
printf("%p\n", (void *) &b);
那么程式必須為這兩個printf陳述句列印不同的值。這是因為在抽象計算機模型中同時存在的不同物件必須具有不同的地址。抽象計算機會為這些列印不同的地址,因此編譯器必須生成一個忠實于該模型的程式。
腳注
1由于嵌套的函式呼叫,一個函式可以同時執行多次。
2有時人們說的生命周期x是函式的作用域,但這是不正確的。該函式可以呼叫另一個例程并傳遞它y,它的地址為x. 然后另一個例程可以x使用這個地址訪問。x即使記憶體不在其他例程的源代碼范圍內,它仍然保留。在子程式呼叫程序中, 的執行foo被暫時掛起,但并未結束,因此 的生命周期x并未結束。
uj5u.com熱心網友回復:
自動變數的生命周期是宣告它的范圍的整個持續時間;在您的情況下,該范圍是整個foo功能。
允許編譯器進行優化(包括完全洗掉變數),但不會產生任何可觀察到的效果;然而,一旦你分配了xto的地址y,那么任何對的使用都*y將被使用x,因此分配給的記憶體x不能再用于其他用途,始終有可能訪問或修改*y。
uj5u.com熱心網友回復:
x 正在被使用,y 正在傳遞它的地址!簡而言之,只要編譯器作者是明智的,答案就是“是”。大多數編譯器(至少是 Visual Studio)不會編譯它,或者至少會警告 x 未初始化,所以這不是一個非常現實的例子。
Y 絕對不能通過改變 x 或 y 以外的其他變數來改變。那是100%。當你進入一個函式時,引數然后區域變數被壓入堆疊,然后當你離開一個函式時,它們被彈出。沒有共享記憶體的范圍(除非您使用聯合)。
這個問題背后的原因是什么?如果你真的想知道 c 是如何定義的,你應該閱讀 Kernighan 和 Ritchie 的“The C Programming Language”
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/425847.html
