2017-07-31 38 views
1

我發現C語言(我是從JavaScript),我有這個簡單的腳本類型的C - 爲什麼我的變量沒有被銷燬?

#include "stdio.h" 

int rand(){ 
    int numb; 
    for (int i = 0; i < 4; ++i) 
    { 
    numb++; 
    } 
    return numb; 
} 

int main(int argc, char const *argv[]) 
{ 
    int a = rand(); 
    int b = rand(); 
    printf("%i , %i\n", a, b); 
    return 0; 
} 

我的問題是,爲什麼我獲得相同的結果(4,8),好像變了declarated靜態&初始化爲0?

static int numb = 0; 

我真的不知道約十分了解變量的作用域:■

謝謝!

+4

你沒有初始化麻木。除非聲明爲「static」,否則它不會保留它在調用之間的值。 –

+0

而不是寫成靜態的。 – lilezek

+6

未定義的行爲''麻木++''。一旦你觸發UB,詢問爲什麼問題就沒有多大意義。 – PSkocik

回答

4

由於本地變量numb未初始化,並且通常具有不確定的值,所以程序具有未定義的行爲。

你的結果用下面的方法解釋。看起來,當函數被調用時,第一次爲變量分配的內存保存爲零。

當函數第二次被調用時,使得該函數對具有自動存儲持續時間的變量使用相同的內存,但通常不需要使用該變量的相同地址。

按照C標準(6.2.4對象的存儲持續時間)

1的對象具有決定其壽命的存儲持續時間。有 四個存儲持續時間:靜態,螺紋,自動的,並且被分配 ...

6對於這樣一個對象,該對象不具有可變長度數組類型, 其壽命從進入到與其關聯的塊,直到該塊的執行以任何方式結束。 (輸入一個 封閉塊或調用一個函數會暫停但不會結束, 執行當前塊。)如果塊是遞歸輸入的,則每次創建該對象的新實例。對象的初始值 是不確定的。如果爲 對象指定了初始化,則在執行該塊時每次執行聲明或複合文字時執行初始化; 否則, 值在每次達到聲明時變得不確定

最後(J.2未定義的行爲)

- 使用自動存儲持續時間的對象的值,而 它是不確定的(6.2.4,6.7.9,6.8)。

+0

對於較小的代碼(如示例),使用相同內存位置的巧合程度較高。 – alvits

+0

@alvits是的,你是對的。 –

+0

好了,我明白編譯器每次調用「rand」函數時都會選擇完全相同的地址,因爲它已經有一個值指向它。所以變量的範圍是主要功能?我的意思是這個值在程序結束時被清除,就是這樣? – nodeover

0

我的問題是,爲什麼我獲得相同的結果(4,8),就好像其中靜態&聲明的變量 初始化爲0?

這是未定義的行爲(UB)。你的觀察僅僅是巧合。用另一個編譯器編譯或在不同的體系結構上編譯,結果可能會有所不同。

你必須自己初始化函數中的整數。

+0

他詢問函數中的變量numb是否被聲明作爲靜態並初始化爲零。他想知道爲什麼每次函數調用時都沒有賦值爲零 –

+3

這不是我怎麼理解的,再次讀到「好像變量被聲明爲靜態並初始化爲0」 - 「好像」。我相信OP瞭解靜態的概念。我猜他對UB的認識並不是很高。 – Elyasin

+0

和函數看起來像這樣'int rand(){ static int numb = 0; for(int i = 0; i <4; ++ i) { numb ++; } 返回麻木; }'。他問爲什麼再次4和8.答案是:functons中聲明的靜態變量只初始化一個,並且當函數被再次調用時它們保持它們的值 –

0

當你調用rand(),在numb變量分配數據堆棧和堆棧指針增加。

當功能結束並返回到main時,分配的數據堆棧被釋放,並且堆棧指針減少(實際內存中的值保持不變)。

當您調用rand()時,numb變量將再次分配到數據堆棧的上一個位置。它沒有初始化,所以以前的值仍然存在...

+0

解釋不錯,但只是執行。這是UB。 – Elyasin

+0

@Mat - 它不必存儲在堆棧中。它可以存儲在寄存器中。但效果是一樣的 - 初始值是隨機的:) –

-2

對於downvoters:它都是在C標準。

3不同的情況

1.Undefined行爲

int foo(){ 
    int numb; 
    for (int i = 0; i < 4; ++i) 
    { 
    numb++; 
    } 
    return numb; 
} 

UB - 沒什麼好解釋的。任何事情都有可能發生

2.自動初始化變量

int foo(){ 
    int numb = 0; 
    for (int i = 0; i < 4; ++i) 
    { 
    numb++; 
    } 
    return numb; 
} 

numb被初始化每個函數被調用和銷燬退出時間爲零。

3.Static初始化變量

int foo(){ 
    static int numb = 0; 
    for (int i = 0; i < 4; ++i) 
    { 
    numb++; 
    } 
    return numb; 
} 

變量被初始化僅僅一次,並保持其值。靜態自動變量的範圍與自動變量的範圍相同,即它在其定義的塊中是本地的 - 在這種情況下爲功能foo,但是在程序生存期內該值保持不變。這些變量只被初始化一次,並在調用之間保持它們的值。如果靜態自動變量未初始化 - 它將在啓動過程中初始化爲默認值 - 這是實現定義的(不包括初始值)(通常是.bss段並初始化爲零)。

源:C標準

具有靜態存儲持續時間的所有對象應被初始化程序啓動前(設置爲 它們的初始值)。這種初始化的方式和時間在其他方面是不明確的。

-

其標識符,而不存儲類 符 _Thread_local被聲明的目的,並且用外部或內部聯動裝置或與存儲類說明靜態的,具有靜態存儲持續時間。它的 生命週期是程序的整個執行過程,它的存儲值 僅在程序啓動之前初始化一次。

-

在初始化所有的表達式爲具有靜態或 線程存儲時間應是常量表達式或字符串 文字的對象。

+1

在2中,它特別不會被積極銷燬(意味着什麼),當它超出範圍,因此觀察到的行爲。 –

+0

@IljaEverilä - 實際上 - 他們是 - 隨着堆棧指針在函數出口處被恢復,所以他們的存儲被主動釋放。並且通過在堆疊上爲它們分配空間來創建它們。當然有時候他們甚至在內存中沒有物理表示,因爲編譯器試圖將它們保存在寄存器中。在「寄存器豐富」的RISC機器上,它最顯着。但它也意味着被破壞,因爲它們被保存的寄存器正在被重用 –

+0

我們使用相同的術語來談論不同的事情。我理解你的帖子意味着「銷燬」意味着例如歸零的空間超出了範圍,或者類似的,至少我已經使用過的編譯器,這當然沒有完成。正如我所看到的,超出範圍與銷燬不同,我的理解更類似於C++(我們有析構函數)等語言的刪除。關於C標準的範圍,不使用「破壞」一詞。 –

相關問題