質問

C、C++、Java の静的変数がデフォルトでゼロで初期化される理由を知りたいです。そして、これがローカル変数には当てはまらないのはなぜでしょうか?

役に立ちましたか?

解決

静的変数は決定的に初期化されるのに、ローカル変数は決定的に初期化されないのはなぜですか?

静的変数がどのように実装されるかを見てください。 これらのメモリはリンク時に割り当てられ、それらの初期値もリンク時に提供されます。 実行時のオーバーヘッドはありません。

一方、ローカル変数用のメモリは実行時に割り当てられます。スタックは成長する必要があります。以前そこに何があったのかわかりません。必要に応じて、そのメモリをクリア (ゼロにする) こともできますが、実行時のオーバーヘッドが発生します。 C++ の哲学は「使用しないものにはお金を払わない」なので、デフォルトではメモリがゼロになりません。

わかりましたが、なぜ静的変数は他の値ではなくゼロに初期化されるのでしょうか?

まあ、通常はその変数を使って何かをしたいと思うでしょう。しかし、初期化されているかどうかはどうやってわかるのでしょうか?静的なブール変数を作成できます。ただし、何か (できれば false) に確実に初期化する必要もあります。 ポインタはどうでしょうか?ランダムなゴミではなく、NULL に初期化するほうがよいでしょう。 構造体/レコードはどうでしょうか?内部には他のデータメンバーがいくつかあります。すべてをデフォルト値に初期化するのが合理的です。ただし、わかりやすくするために、「0 に初期化」戦略を使用する場合は、個々のメンバーを調べてその型をチェックする必要はありません。 メモリ領域全体を0に初期化するだけです。

これは実際には技術的な要件ではありません。デフォルト値が 0 以外の場合でも、初期化のセマンティクスは正常であると考えられますが、依然として決定的です。しかし、ではその値はどうあるべきなのでしょうか?0 が使用される理由は非常に簡単に説明できますが (確かに少し恣意的に聞こえますが)、-1 や 1024 を説明するのはさらに難しいようです (特に、変数がその値を保持できるほど大きくない可能性があるなど)。

また、変数はいつでも明示的に初期化できます。

そして、C++ 標準のパラグラフ 8.5.6 には、「静的ストレージ期間のすべてのオブジェクトは、プログラムの起動時にゼロで初期化されるものとする」という規定があります。

詳細については、次の他の質問を参照してください。

他のヒント

C ++標準状態の

段落8.5.6そのます:

「静的記憶域期間のすべてのオブジェクトは、プログラム起動時にゼロに初期化されなければならない」

(標準はまた、ローカル変数の初期化が定義されていないと述べている)。

理由として、標準では言っていません。)一つの推測は、それがいかなる追加の欠点なしに実装する合理的に簡単だということです。

Java用のスピーキングます:

あなたがそれにアクセスする前に、それは安全ゲインだからローカル変数は、初期化する必要があります。あなたのためのコンパイラチェックし、変数が間違いなく設定されている場合。

静的またはクラス変数(オブジェクトタイプと)それらはコンパイル時に初期化された場合、コンパイラがチェックすることはできませんので、nullで初期化されています。代わりに、プログラムをさせるのは、それが非初期化された変数にアクセスする場合、それはnullとの暗黙の初期化されます失敗します。

ネイティブ型を持つ変数がnull値を取得することはできませんので、非ローカル変数は、フォールバックとして、0またはfalseで初期化されています。それは確かに、最善の解決策ではないのですが、私はより良いものを知りません。 ; - )

したがって、これらはある程度、言語設計者の側での設計上の決定にすぎません。しかし、Java でこれらの決定が行われる考えられる理由は次のとおりです。

  • 静的/メンバー変数の場合、それらを何かに初期化する場合は、ゼロが便利な値です。その理由は、(a) 一般に「特別な値に設定されていない」ことを意味するのに適した値であり、この値が得られる値であるためです。カウンターなどの場合にはとにかく選ばれます。(b) 内部的には、特にオブジェクト参照の場合に null を表すために、ゼロを「特別な」値に使用できる可能性があります。
  • ローカル変数の場合、デフォルトを指定しないと、変数が読み取られる前にプログラマに何らかの値を強制的に設定するルールが許可されます。これは、コンパイラが特定のエラーを検出できるようにするのに実際に役立ちます。

ローカル変数の場合、ローカル変数が宣言されたとしても (これは、バイトコード/マシンコード レベルで本質的にスタック領域の割り当て/スタック ポインタの移動を意味します)、特定のコード パスで実際に書き込み/読み取りが行われないことも考えられます。したがって、デフォルトを設定しないと、そのような場合にデフォルトを設定するという不必要な作業を回避できます。

ただし、繰り返しますが、これらはある程度設計上の決定です。これらは基本的に、JVM 実装にとって便利なものとプログラマにとって便利なものとの間のトレードオフです。

注:C/C++ では、「静的」変数は Java の静的変数とは意味が異なります。

私は、Javaについて見当がつかないと私はそれがJavaで静的/地元の人々のために違うの疑います。

CおよびC ++用として、それはプログラマがコードの影響を気にしてコントロールにいる愛することです。ローカル変数を初期化するたびにプログラムが適用範囲に入る余分なコードの実行を暗示します。災害かもしれ頻繁に呼び出される関数についてます。

これは、C / C ++で「のみ使用するもののために支払う」の概念に関係しています。

静的変数の場合、初期化コードを生成することなく行うことができます。オブジェクトファイルは、データセグメント内の変数の初期値が含まれており、OSは実行可能なIT負荷をロードし、プログラムが実行を開始する前に、このデータ・セグメントをマップするときます。

彼らは一度初期化されていないため、ローカル変数の場合、コードなしでそれらを初期化する方法はありません、彼らはあなたがその範囲に入るたびに初期化する必要があります。また、彼らは、スタックに割り当てられ、割り当てが発生したときに一般的なケースでは、スタック内の初期値は、(あなたはそれが以前に成長してきたよりも多くのスタックを育て、それらの稀な瞬間を除く)の前にあっただけで何ですされます。

だから、暗黙的にコンパイラは、プログラマが明示的にかなりその「哲学」に反している、そうすることを指令せずにコードを生成する必要がありますローカル変数を初期化します。

プログラムがその範囲に入ったときに

のJavaについて、私の知る限りでは、変数は常に関係なく、彼らは静的であるか、そうでなければ、初期化されていません。それらの間の唯一の大きな違いは、静的変数のスコープはプログラム全体であるということです。ことを考えると、動作はそれらのすべての間で一貫してます。

これは単なる推測ですが、それはそれは実装が容易、かつ有用なので、それは静力学のためのある方法かもしれません。

コンパイラは、一つcontigousメモリ領域にすべての変数を共割り当て、その後のいずれかmemset()が呼び出される前に、それをクリアするコード(単一main()コール)を発することができます。その形式は、「 BSSをサポートしている場合、多くの場合、それはまた、オペレーティングシステムの実行可能ファイルフォーマットの機能に依存することができます代わりにローダによってクリアされるセクション」を、。これは、実行可能ファイルにスペースを節約し、あなたが持っている可能性があります。

static unsigned char megabyte[1 << 20];

と実行はメガバイトで成長しない。

ローカル変数の場合、これらのどれも適用されません。彼らは(通常はスタック上)「オンザフライ」に割り当てられていると、彼らは通常、とにかく非常にすぐに割り当てることになるだろうので、それらをクリアするためにリソースの無駄になります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top