簡體   English   中英

靜態變量初始化?

[英]Static variable initialization?

我想知道為什么C,C ++和Java中的靜態變量默認初零歸零? 為什么局部變量不是這樣呢?

為什么靜態變量是確定性初始化而局部變量不是?

了解如何實現靜態變量。 它們的內存在鏈接時分配,並且它們的初始值也在鏈接時提供。 沒有運行時開銷。

另一方面,局部變量的內存在運行時分配。 堆棧必須增長。 你不知道之前有什么。 如果需要,可以清除該內存(零),但這會導致運行時開銷。 C ++哲學是“你不為你不使用的東西買單”,所以默認情況下它不會將內存歸零。

好的,但為什么靜態變量初始化為零,而不是其他值?

好吧,你通常想用這個變量做點什么。 但那你怎么知道它是否已被初始化? 您可以創建一個靜態布爾變量。 但是它也必須可靠地初始化為某種東西(最好是假的)。 指針怎么樣? 你寧願把它初始化為NULL而不是一些隨機垃圾。 結構/記錄怎么樣? 它里面還有一些其他的數據成員。 將所有這些值初始化為默認值是有意義的。 但為簡單起見,如果使用“初始化為0”策略,則不必檢查單個成員並檢查其類型。 您只需將整個內存區域初始化為0即可。

這不是真正的技術要求。 如果默認值不是0,但仍然是確定性的,那么初始化的語義仍然可以被認為是合理的。 但那么,這個價值應該是什么? 你可以很容易地解釋為什么使用0(雖然它確實聽起來有點武斷),但是解釋-1或1024似乎更難(尤其是變量可能不足以容納該值,等等)。

並且您始終可以顯式初始化變量。

並且您始終擁有C ++標准的第8.5.6段,其中說“靜態存儲持續時間的每個對象都應在程序啟動時進行零初始化”。

有關詳細信息,請參閱以下其他問題:

C ++標准的第8.5.6段規定:

“靜態存儲持續時間的每個對象都應在程序啟動時進行零初始化”

(標准還說局部變量的初始化是未定義的)

至於為什么,標准沒有說;)一個猜測是,它的實施相當容易,沒有任何額外的缺點。

說到java:

必須先初始化局部變量才能訪問它,因為這是一個安全的好處。 如果確定變量,編譯器會檢查您。

static或類變量(使用Object類型)使用null初始化,因為編譯器無法檢查它們是否在編譯時初始化。 如果程序訪問非初始化變量,則不會讓程序失敗,而是使用null隱式初始化程序。

具有本機類型的變量無法獲取null值,因此非局部變量初始化為0false ,作為回退。 當然,這不是最佳解決方案,但我不知道更好的解決方案。 ;-)

所以在某種程度上,這些只是語言設計者的設計決策。 但是在Java中做出這些決定的可能原因是:

  • 對於靜態/成員變量,如果你要將它們初始化為某個東西,則零是一個方便的值,因為(a)它通常是一個合適的值,意思是“沒有設置為任何其他特殊的”,並且是你將擁有的值無論如何在某些情況下,例如櫃台; (b)在內部,零可以用於“特殊”值,特別是在對象引用的情況下表示null。
  • 對於局部變量,給它們沒有默認允許強制程序員在讀取變量之前設置一些值的規則,這實際上可以用於允許編譯器發現某些錯誤。

在局部變量的情況下,也可以想到可以聲明局部變量(在字節碼/機器代碼級別實質上意味着分配堆棧空間/移動堆棧指針)但是然后從未在特定代碼路徑中實際寫入/讀取。 因此,沒有默認值可以避免在這些情況下進行不必要的設置默認操作。

不過,我再說一遍,這些都是設計決定。 它們本質上是在JVM實現方便和程序員方便之間的權衡。

NB在C / C ++中,“靜態”變量對Java中的靜態變量意味着不同的東西!

我不知道java,我懷疑它與java中的靜態/本地不同。

至於c和c ++,它是關於程序員關心他們的代碼效果和喜歡控制。 每次程序進入范圍時,初始化局部變量都意味着執行額外的代碼。 對於經常被稱為可能是災難的功能。

這與C / C ++中“僅為你使用的東西付費”的概念有關。

對於靜態變量,可以在不生成代碼的情況下進行初始化。 目標文件包含數據段中變量的初始值,當OS加載可執行文件時,它會在程序開始執行之前加載並映射此數據段。

對於局部變量,沒有代碼就無法初始化它們,因為它們沒有初始化一次,每次進入它們的范圍時都應該初始化它們; 它們也被分配在堆棧中,並且當分配發生時,一般情況下堆棧中的初始值就是之前的情況(除了那些罕見的時刻,你比以前增長了更多的堆棧)。

因此,為了隱式初始化一個局部變量,編譯器需要生成代碼而程序員沒有明確命令它這樣做,這完全違背了“哲學”。

關於Java,據我所知,變量總是在程序進入其范圍時初始化,無論它們是否是靜態的。 它們之間唯一顯着的區別是靜態變量的范圍是整個程序。 鑒於此,所有這些行為都是一致的。

這只是一個猜測,但它可能是靜態的方式,因為它易於實現,並且很有用。

編譯器可以將所有變量共同分配到一個連續的內存區域,然后在調用main()之前發出代碼(單個memset()調用)以清除它。 在許多情況下,它還可以依賴操作系統的可執行文件格式的功能,如果該格式支持“ bss部分” ,則由加載程序清除。 這可以節省可執行文件中的空間

static unsigned char megabyte[1 << 20];

並且可執行文件不會增長一兆字節。

對於局部變量,這些都不適用; 它們是“動態”分配的(通常在堆棧上),清除它們將浪費資源,因為它們通常很快就會分配給它們。

暫無
暫無

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

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