遭遇する可能性のある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つのコピー(ところで、memcpy
gccの奇妙な呼び出しではない場合があります)でした。そのため、プロジェクトの最もホットな関数で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ビットでは非常に低速です)、inline
500行であってもすべての関数を作成します(__attribute__((always_inline))
コンパイラが必要としない場合に使用)