Win32 APIプログラミングでは、複数のフィールドでC struct
sを使用するのが一般的です。通常、意味のある値を持っているのはそのうちの2つだけで、他のすべてはゼロにする必要があります。これは、次の2つの方法のいずれかで実現できます。
STRUCT theStruct;
memset( &theStruct, 0, sizeof( STRUCT ) );
または
STRUCT theStruct = {};
2番目のバリアントはよりきれいに見えます-ワンライナーで、タイプミスがあり、エラーが発生する可能性のあるパラメーターはありません。
最初のバリアントと比較して欠点はありますか?使用するバリアントとその理由
これらの2つの構成は、意味が異なるveryを構成します。最初のものはmemset
関数を使用します。これはメモリのバッファを特定の値に設定するを目的としています。 2番目のオブジェクトの初期化。少しのコードで説明しましょう:
メンバーを持つ構造があると仮定しましょうPODタイプのみ
_struct POD_OnlyStruct
{
int a;
char b;
};
POD_OnlyStruct t = {}; // OK
POD_OnlyStruct t;
memset(&t, 0, sizeof t); // OK as well
_
この場合、_POD_OnlyStruct t = {}
_またはPOD_OnlyStruct t; memset(&t, 0, sizeof t)
を書いてもそれほど違いはありません。ここにある唯一の違いはalignmentバイトが0に設定されているからです。 memset
のケースが使用されます。通常はこれらのバイトにアクセスできないため、違いはありません。
一方、質問にC++のタグを付けたので、メンバーPODとは異なるタイプの別の例を試してみましょう。
_struct TestStruct
{
int a;
std::string b;
};
TestStruct t = {}; // OK
{
TestStruct t1;
memset(&t1, 0, sizeof t1); // ruins member 'b' of our struct
} // Application crashes here
_
この場合、_TestStruct t = {}
_のような式を使用するのが適切であり、memset
を使用するとクラッシュにつながります。 memset
を使用すると、次のようになります。タイプTestStruct
のオブジェクトが作成され、構造体のメンバーであるため、タイプ_std::string
_のオブジェクトが作成されます。次に、memset
は、オブジェクトb
が配置されたメモリを特定の値、たとえばゼロに設定します。これで、TestStructオブジェクトがスコープ外に出ると破棄され、そのメンバーの_std::string b
_になったときにクラッシュが発生します。そのオブジェクトの内部構造はすべてmemset
によって破壊されたためです。
つまり、現実はこれらは非常に異なるであり、特定の場合にmemset
構造全体をゼロにする必要がある場合がありますが、何をしているかを理解することは常に重要です。 2番目の例のように間違えないでください。
私の投票-オブジェクトでmemset
を使用してくださいのみ必要な場合、およびdefault初期化_x = {}
_を他のすべての場合に使用してください。
構造体のメンバーによっては、2つのバリアントは必ずしも同等ではありません。 memset
は構造体をall-bits-zeroに設定しますが、値の初期化はすべてのメンバーを値0に初期化します。 C標準では、これらが整数型に対してのみ同じであることが保証されており、浮動小数点値またはポインターに対しては同じではありません。
また、一部のAPIでは、構造を実際にall-bits-zeroに設定する必要があります。たとえば、BerkeleyソケットAPIは構造を多相的に使用するため、明らかな値だけでなく、構造全体を実際にゼロに設定することが重要です。 APIのドキュメントには、構造を実際にすべてビットゼロにする必要があるかどうかが記載されている必要がありますが、不足している可能性があります。
しかし、これらのいずれか、または同様のケースが当てはまらない場合、それはあなた次第です。構造を定義するときは、値の初期化を優先します。これは、意図をより明確に伝えるためです。もちろん、既存の構造をゼロ化する必要がある場合は、memset
が唯一の選択肢です(まあ、各メンバーを手動でゼロに初期化することは別ですが、特に大きな構造の場合は通常行われません)。
構造体に次のようなものが含まれている場合:
int a;
char b;
int c;
次に、「b」と「c」の間にパディングのバイトが挿入されます。 memset()はそれらをゼロにしますが、他の方法はそうしないので、3バイトのゴミがあります(intが32ビットの場合)。構造体を使用してファイルの読み取り/書き込みを行う場合、これは重要です。
あなたが言及したように、それはきれいに見え、エラーが発生しにくいため、値の初期化を使用します。私はそれをすることにどんな欠点も見ません。
ただし、memset
を使用して、構造体を使用した後に構造体をゼロにすることができます。
一般的ではありませんが、2番目の方法には、floatをゼロに初期化する利点もあると思います。 memsetを実行すると、確かに
一部のコンパイラでは、_STRUCT theStruct = {};
_は実行可能ファイルでmemset( &theStruct, 0, sizeof( STRUCT ) );
に変換されます。一部のC関数は、ランタイムセットアップを行うために既にリンクされているため、コンパイラはmemset/memcpyなどのこれらのライブラリ関数を使用できます。
コンパイル時に実行できるため、値の初期化。
また、すべてのPODタイプを正しく0に初期化します。
Memset()は実行時に行われます。
また、構造体がPODでない場合、memset()の使用は疑わしいです。
非int型を正しく(ゼロに)初期化しません。