9

最近、テスト結果を検証するために2つのファイル(ゴールデンと期待)を比較する必要があり、両方のファイルに書き込まれたデータが同じであるにもかかわらず、ファイルが一致しないというケースに遭遇しました。

さらに調査したところ、いくつかの整数と64バイトのchar配列を含む構造があり、ほとんどの場合、char配列のすべてのバイトが使用されているわけではなく、配列の未使用のフィールドにランダムデータが含まれていることがわかりました。不一致を引き起こしていました。

これにより、Javaで行われるように、C /C++でも配列を初期化するのが良い方法かどうかという質問がありました。

4

8 に答える 8

23

メモリ/変数を使用する前に初期化することをお勧めします。初期化されていない変数はバグの大きな原因であり、追跡が非常に難しいことがよくあります。

すべてのデータを初期化することは、ファイル形式に書き込むときに非常に良いアイデアです。ファイルの内容がクリーンに保たれるため、操作が簡単になり、初期化されていないデータを誰かが誤って「使用」しようとした場合に問題が発生しにくくなります(覚えておいてください)。将来的にデータを読み取る独自のコードであるだけでなく、ファイルをはるかに圧縮可能にします。

変数を使用する前に変数を初期化しない唯一の理由は、初期化が技術的に「不要」であり、かなりのオーバーヘッドが発生する、パフォーマンスが重要な状況にある場合です。ただし、ほとんどの場合、変数を初期化しても重大な害は発生しませんが(特に、変数が使用される直前に宣言されている場合)、一般的なバグの原因を排除することで、開発時間を大幅に節約できます。

于 2010-01-11T07:01:08.573 に答える
6

配列で未定義の値を使用すると、未定義の動作が発生します。したがって、プログラムは自由に異なる結果を生成できます。これは、ファイルがわずかに異なるか、プログラムがクラッシュするか、プログラムがハードドライブをフォーマットするか、プログラムによってデーモンがユーザーの鼻から飛び出すことを意味する場合があります(http://catb.org/jargon/html/N/ nasal-demons.html

これは、配列を作成するときに配列値を定義する必要があるという意味ではありませんが、使用する前に配列値を初期化する必要があります。もちろん、これを確実にする最も簡単な方法は、アレイを作成するときにこれを行うことです。

MyStruct array[10];
printf( "%f", array[2].v ); // POTENTIAL BANG!
array[3].v = 7.0;
...
printf( "%f", array[3].v ); // THIS IS OK.

PODの巨大な配列の場合、すべてのメンバーをゼロに初期化するための優れた省略形があることを忘れないでください

MyPODStruct bigArray[1000] = { 0 };
于 2010-01-11T07:16:16.780 に答える
4

私は、そうすることが「バグの一般的な原因を排除する」または「そうしないとプログラムの正確性を台無しにする」という与えられた意見に強く反対します。プログラムが単一化された値で動作する場合、バグがあり、正しくありません。値を初期化しても、最初の使用時に期待される値がまだ得られないことが多いため、このバグを排除することはできません。ただし、ランダムなガベージが含まれている場合、プログラムは試行のたびにランダムにクラッシュする可能性が高くなります。常に同じ値を使用すると、クラッシュ時の動作がより確定的になり、デバッグが容易になる場合があります。

特定の質問については、未使用の部分をファイルに書き込む前に上書きすることもお勧めします。これは、パスワードなど、以前に使用したくない部分が含まれている可能性があるためです。

于 2010-01-11T08:22:38.887 に答える
1

C ++配列の値を初期化しない場合、値は何でもかまいません。したがって、予測可能な結果が必要な場合は、値をゼロにすることをお勧めします。

ただし、nullで終了する文字列のようにchar配列を使用する場合は、適切な関数を使用してファイルに書き込むことができるはずです。

C ++では、より多くのOOPソリューションを使用する方が良い場合があります。IEベクトル、文字列など。

于 2010-01-11T06:52:13.557 に答える
1

アレイを初期化しないでおくと、パフォーマンスなどの利点がある場合があることに注意してください。

初期化されていない配列からの読み取りは悪いだけです。初期化されていない場所から読み取ることなくそれらを持ち歩くことは問題ありません。

さらに、プログラムに配列内の初期化されていない場所から読み取るバグがある場合、すべての配列を既知の値に防御的に初期化することで「カバーする」ことはバグの解決策ではなく、後でしか表面化できません。

于 2010-01-11T10:54:29.110 に答える
1

遭遇する可能性のある2つのスタイルの違いについて、大きな記事を書くことができます。変数を宣言するときに常に変数を初期化する人と、必要に応じて変数を初期化する人です。私は最初のカテゴリーにいる誰かと大きなプロジェクトを共有し、今では間違いなく2番目のタイプになっています。常に変数を初期化すると、そうでない場合よりも微妙なバグや問題が発生します。私が見つけたケースを思い出しながら、その理由を説明しようと思います。最初の例:

struct NODE Pop(STACK * Stack)
{
  struct NODE node = EMPTY_STACK;

  if(Stack && Stack->stackPointer)
    node = Stack->node[--Stack->stackPointer];

  return node;
}

これは他の人によって書かれたコードでした。この関数は、アプリケーションで最もホットな関数です(三分木で、500 000 000文のテキストインデックスを想像します。再帰関数呼び出しを使用したくないため、FIFOスタックを使用して再帰を処理します)。変数の体系的な初期化のため、これは彼のプログラミングスタイルの典型でした。そのコードの問題memcpyは、初期化の非表示と構造体の他の2つのコピー(ところで、memcpygccの奇妙な呼び出しではない場合があります)でした。そのため、プロジェクトの最もホットな関数で3つのコピーと非表示の関数呼び出しがありました。に書き直します

struct NODE Pop(STACK * Stack)
{
  if(Stack && Stack->stackPointer)
    return Stack->node[--Stack->stackPointer];
  return EMPTY_STACK;
}

memcpyコピーは1つだけです(そして、それが実行されるSPARCの補足的な利点であり、この関数は、への呼び出しが回避され、新しいレジスタウィンドウを構築する必要がないため、リーフ関数です)。したがって、関数は4倍高速でした。

私がオンスを見つけた別の問題は、正確にどこにあるか覚えていません(したがって、コード例はありません、申し訳ありません)。宣言時に初期化されたがswitch、有限状態オートマトンでループで使用された変数。初期化値がオートマトンの状態の1つではなく、非常にまれなケースで、オートマトンが正しく機能しなかったという問題がありました。イニシャライザーを削除することにより、コンパイラーが発行した警告により、変数が適切に初期化される前に使用できることが明らかになりました。当時、オートマトンの修正は簡単でした。 道徳:変数を防御的に初期化すると、コンパイラの非常に有用な警告が抑制される場合があります。

結論:変数を賢く初期化します。体系的にそれを行うことは、カーゴカルトに従うことに他なりません(仕事中の私の相棒は想像できるより悪いカーゴカルトです、彼はgotoを決して使用せず、常に変数を初期化し、多くの静的宣言を使用します(それはあなたがたが知っているより速いです(それは実際、SPARC 64ビットでは非常に低速です)、inline500行であってもすべての関数を作成します(__attribute__((always_inline))コンパイラが必要としない場合に使用)

于 2010-04-16T18:37:58.440 に答える
0

まず、配列や変数などを初期化する必要があります。そうしないと、プログラムの正確性が損なわれます。

第二に、この特定のケースでは、配列を初期化しないことは元のプログラムの正確さに影響を与えなかったようです。代わりに、ファイルを比較することを目的としたプログラムは、ファイルが意味のある方法(最初のプログラムで定義された「意味のある」)で異なるかどうかを判断するために使用されるファイル形式について十分に認識していません。

元のプログラムについて文句を言う代わりに、問題のファイル形式についてもっと知るために比較プログラムを修正します。ファイル形式が十分に文書化されていない場合は、不満を言う正当な理由があります。

于 2010-01-11T07:49:47.913 に答える
0

C ++の良い習慣は、配列の代わりにstd ::vector<>を使用することだと思います。もちろん、これはCには無効です。

于 2010-01-11T08:23:45.927 に答える