web-dev-qa-db-ja.com

オブジェクトを初期化するとき、{0}はどういう意味ですか?

{0}を使用してオブジェクトを初期化する場合、それはどういう意味ですか? {0}への参照はどこにも見つかりません。中括弧があるため、Google検索は役に立ちません。

サンプルコード:

SHELLEXECUTEINFO sexi = {0}; // what does this do?
sexi.cbSize = sizeof(SHELLEXECUTEINFO);
sexi.hwnd = NULL;
sexi.fMask = SEE_MASK_NOCLOSEPROCESS;
sexi.lpFile = lpFile.c_str();
sexi.lpParameters = args;
sexi.nShow = nShow;

if(ShellExecuteEx(&sexi))
{
    DWORD wait = WaitForSingleObject(sexi.hProcess, INFINITE);
    if(wait == WAIT_OBJECT_0)
        GetExitCodeProcess(sexi.hProcess, &returnCode);
}

これがないと、上記のコードは実行時にクラッシュします。

249

ここで起こっていることは、aggregate初期化と呼ばれます。 ISO仕様のセクション8.5.1の集約の定義(略称)は次のとおりです。

集合体は、ユーザーが宣言したコンストラクター、プライベートまたは保護された非静的データメンバー、基本クラス、および仮想関数を持たない配列またはクラスです。

さて、{0}を使用してこのように集約を初期化することは、基本的に0全体に対するトリックです。これは、集計の初期化を使用する場合、すべてのメンバーを指定する必要はなく、仕様では未指定のすべてのメンバーをデフォルトで初期化する必要があるためです。単純型の場合は0に。

仕様からの関連する引用は次のとおりです。

リスト内の初期化子が集約内のメンバーよりも少ない場合、明示的に初期化されていない各メンバーはデフォルトで初期化されます。例:

struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };

ss.a1で初期化し、ss.b"asdf"で初期化し、ss.cint()形式の式の値で初期化します。つまり、0

このトピックの完全な仕様を見つけることができます here

298
Don Neufeld

知っておくべきことの1つは、この手法ではパディングバイトがゼロに設定されないことです。例えば:

struct foo
{
    char c;
    int  i;
};

foo a = {0};

次と同じではありません:

foo a;
memset(&a,0,sizeof(a));

最初のケースでは、cとiの間の埋め込みバイトは初期化されていません。なぜ気にしますか?このデータをディスクに保存する場合、またはネットワークなどで送信する場合は、セキュリティ上の問題が発生する可能性があります。

89
Harold Ekstrom

空の集計イニシャライザも機能することに注意してください。

SHELLEXECUTEINFO sexi = {};
char mytext[100] = {};
20
dalle

文字列を初期化するためにも使用します。

char mytext[100] = {0};
7
Adam Pierce

{0}は、CとC++の両方の(完全なオブジェクト)型の有効な初期化子です。これは、オブジェクトをzeroに初期化するために使用される一般的なイディオムです(その意味を読んでください)。

スカラー型(算術型およびポインター型)の場合、中括弧は不要ですが、明示的に許可されます。 N1570ドラフト ISO C規格のセクション6.7.9を引用:

スカラーの初期化子は、オプションで中括弧で囲まれた単一の式でなければなりません。

オブジェクトをゼロに初期化します(整数の場合は0、浮動小数点の場合は0.0、ポインターの場合はNULLポインター)。

非スカラー型(構造体、配列、共用体)の場合、{0}は、オブジェクトのfirst要素がゼロに初期化されることを指定します。構造、構造の配列などを含む構造の場合、これは再帰的に適用されるため、最初のスカラー要素はタイプに応じてゼロに設定されます。初期化子と同様に、指定されていない要素はゼロに設定されます。

中間括弧({})は省略できます。たとえば、これらは両方とも有効かつ同等です。

int arr[2][2] = { { 1, 2 }, {3, 4} };

int arr[2][2] = { 1, 2, 3, 4 };

これが、たとえば、最初の要素が非スカラーである型に対して{ { 0 } }を記述する必要がない理由です。

したがって、この:

some_type obj = { 0 };

は、objをゼロに初期化する簡単な方法です。つまり、objの各スカラーサブオブジェクトは、整数の場合は0に、浮動小数点の場合は0.0に設定されます。 、またはポインターの場合はNULLポインター。

ルールはC++でも同様です。

特定のケースでは、sexi.cbSizeなどに値を割り当てているため、SHELLEXECUTEINFOが構造体またはクラス型(またはおそらくユニオンですが、おそらくそうではない)であることは明らかです。これは当てはまりますが、{ 0 }は、より一般的な状況で使用できる一般的なイディオムです。

これは、not(必然的に)memsetを使用してオブジェクトの表現をall-bits-zeroに設定することと同等です。浮動小数点0.0もNULLポインターも必ずしもすべてゼロのビットとして表されるわけではなく、{ 0 }イニシャライザーは必ずしもパディングバイトを特定の値に設定するわけではありません。ただし、ほとんどのシステムでは、同じ効果が得られる可能性があります。

7
Keith Thompson

私はc/c ++で働いていましたが、IIRCからしばらく経ちましたが、同じショートカットを配列にも使用できます。

3
µBio

私はいつもなぜと思っていました

struct foo bar = { 0 };

以下に説明するテストケースを示します。

check.c

struct f {
    int x;
    char a;
} my_zero_struct;

int main(void)
{
    return my_zero_struct.x;
}

gcc -O2 -o check check.cでコンパイルしてから、readelf -s check | sort -k 2でシンボルテーブルを出力します(これは、x64システムのubuntu 12.04.2のgcc 4.6.3で使用されます)。抜粋:

59: 0000000000601018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
48: 0000000000601018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
25: 0000000000601018     0 SECTION LOCAL  DEFAULT   25 
33: 0000000000601018     1 OBJECT  LOCAL  DEFAULT   25 completed.6531
34: 0000000000601020     8 OBJECT  LOCAL  DEFAULT   25 dtor_idx.6533
62: 0000000000601028     8 OBJECT  GLOBAL DEFAULT   25 my_zero_struct
57: 0000000000601030     0 NOTYPE  GLOBAL DEFAULT  ABS _end

ここで重要なのは、my_zero_struct__bss_startの後であることです。 Cプログラムの「.bss」セクションは、ゼロに設定されるメモリのセクションですbeforemainが呼び出される .bss のウィキペディア。

上記のコードを次のように変更した場合:

} my_zero_struct = { 0 };

次に、結果の「check」実行可能ファイルは、少なくともubuntu 12.04.2上のgcc 4.6.3コンパイラと同じexactlyに見えます。 my_zero_structはまだ.bssセクションにあるため、mainが呼び出される前に自動的にゼロに初期化されます。

コメントのヒント、memsetが "full"構造を初期化する可能性もあります。これは、.bssセクションが完全にクリアされるためです。

mightC言語標準ではこれについて言及されていないかもしれませんが、実際のCコンパイラでは、これまでに別の動作を見たことはありません。

2
Ingo Blackman