変数の初期化を飛び越えるのは不適切な形式ですか、それとも未定義の動作を引き起こしますか?


17

このコードを考えてみましょう:

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

へのジャンプが変数の初期化をバイパスするため、GCCとClang はそれを拒否しbar:ます。MSVCはまったく文句を言いません(xafter を使用bar:すると警告が表示されます)。

同じことをaで行うことができますswitch

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

3つのコンパイラすべてがエラーを出力するようになりました

これらのスニペットの形式は不適切ですか?または、それらはUBを引き起こしますか?

以前はどちらも形式が正しくないと思っていましたが、標準の魅力的な部分を見つけることができません。[stmt.goto]は、このことについて何も言われ、どちらもしないん[stmt.select]


1
xジャンプ後に使用する場合、問題はより簡単になります。
Jarod42

1
標準ではありませんが、ここでいくつかの情報を見つけることができます:en.cppreference.com/w/cpp/language/goto 特に:「制御の転送が自動変数のスコープに入る場合(たとえば、宣言を飛び越えて移動した場合)声明)、プログラムは悪いが形成される(コンパイルすることはできません)、しない限り...」
idclev 463035818

/permissive-MSVCにフラグを追加すると、メッセージも表示されます。ただし、そのフラグのないMSVCの動作が明確に定義されているかどうかはわかりません(そうだとすれば、そうでないとなぜ許可されるのでしょうか?)。
クルミ

@walnut 「そうでなければ、なぜそれを許可するのか」おそらく下位互換性のためか、標準をあまり気にしません。すべての主要なコンパイラは、デフォルト設定では標準に準拠していません。
HolyBlackCat

回答:


20

初期化が空でない場合は、形式が正しくありません。

[stmt.dcl]

3ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法では実行できません(条件およびinitステートメント内の宣言を含む)。自動ストレージ期間を持つ変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数に空の初期化([basic.life])がない限り、形式が正しくありません。このような場合、空の初期化を伴う変数は、宣言された順に構築されます。

イニシャライザは、初期化を非空にします。対照的に、これは

void foo()
{
    goto bar;
    int x; // no initializer
    bar: ;
}

整形式になります。ただし、x不確定な値での使用に関する通常の注意事項が適用されます。


とにかく、変数宣言はスコープの最初のものである必要はありませんか?
ランチャー

4
@Cruncher-C89はそれを要求した。C ++はこれを行ったことはなく、最近のCも行っていません。
StoryTeller-Unslander Monica

3

gotoステートメントから:

制御の移動が自動変数のスコープに入る場合(たとえば、宣言ステートメントを前方にジャンプすることにより)、スコープに入るすべての変数に

  1. 初期化子なしで宣言されたスカラー型
  2. 初期化子なしで宣言された自明なデフォルトコンストラクターおよび自明なデストラクタを持つクラス型
  3. 上記のいずれかのcv認定バージョン
  4. 上記のいずれかの配列
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.