4

「ケース ラベルにジャンプ」エラーに関するこの質問を読みましたが、まだいくつか質問があります。Ubuntu 12.04 で g++ 4.7 を使用しています。

このコードはエラーを返します:

int main() {
  int foo = 1;
  switch(foo) {
  case 1:
    int i = 0;
    i++;
    break;
  case 2:
    i++;
    break;
  }
}

エラーは

jump-to-case-label.cpp: In function ‘int main()’:
jump-to-case-label.cpp:8:8: error: jump to case label [-fpermissive]
jump-to-case-label.cpp:5:9: error:   crosses initialization of ‘int i’

ただし、このコードは正常にコンパイルされ、

int main() {
  int foo = 1;
  switch(foo) {
  case 1:
    int i;
    i = 0;
    i++;
    break;
  case 2:
    i++;
    break;
  }
}

2 番目のコードは最初のコードよりも危険性が低いですか? なぜg ++がそれを許可するのか混乱しています。

次に、この問題の修正は、初期化された変数のスコープを設定することです。初期化された変数が大きなオブジェクトで、switch文がwhileループになっていると、そのスコープに出入りするたびにコンストラクタとデストラクタが呼び出されて効率が低下するのではないか? または、コンパイラはこれを最適化しますか?

4

4 に答える 4

6

オブジェクトが type であっても、オブジェクトの初期化を飛び越えることは、int常に未定義の動作です。-statement のステートメントは特別なものではないことに注意してくださいswitch: これは単なるステートメントであり、人々はこの興味深い方法を [悪用] しています (たとえば、Duff's Deviceなど) 。ステートメント内で唯一特別な点は、ラベルが and の形式を取ることができることdefault:ですcase <const-integer-expr>:

ステートメントint i;は変数の定義ですが、初期化はありません。したがって、変数の初期化はバイパスされません。そもそも、この定義を飛び越えても大きな問題はありません。もちろん、ジャンプするcase 1:ときではなく、ジャンプするときに値が割り当てられますが、これは、変数のみを定義する場合に -statementscase 2:の外側のコードで発生することと同じです。switch

于 2012-10-20T20:07:22.903 に答える
2

switch最初に、コンパイラはアセンブリコードを開く方法を決定します。としてテーブルであるifか、テーブルである可能性がありますgoto。また、変数の初期化を一緒に宣言すると、コンパイラはこれがであると言いますerror。別の場合はそうなりますwarning(コンパイラは警告しますが、抵抗しません)。だから、あなたは自分自身を守ることができます。コンパイラオプションを調整するだけwarningsですerrors。また、内の変数を正しく機能させるにはswitch、それらのスコープを指定する必要があります。例えば:

switch(i)
{
case 1:
{
  int j = 0;
}
break;
}

PS。C ++の場合、スイッチは地獄です。

C ++ 11から:

C.1.5条項6:ステートメント

6.4.2、6.6.4(switchおよびgotoステートメント)

変更:明示的または暗黙的な初期化子を使用して宣言をジャンプすることは無効になりました(ブロック全体が入力されていない場合を除く)

理論的根拠:初期化子で使用されるコンストラクターは、ブロックを離れるときに割り当て解除する必要のあるリソースを割り当てる場合があります。初期化子を飛び越えて許可するには、実行時の割り当ての複雑な決定が必要になります。さらに、初期化されていないオブジェクトを使用すると、災害が発生する可能性があります。この単純なコンパイル時の規則により、C ++は、初期化された変数がスコープ内にある場合、それが確実に初期化されていることを保証します。

元の機能への影響:意味的に明確に定義された機能の削除。

gcc診断プラグマから:

6.57.1​​0診断プラグマ 診断プラグマ

GCCを使用すると、ユーザーは特定の種類の診断を選択的に有効または無効にしたり、診断の種類を変更したりできます。たとえば、プロジェクトのポリシーでは、すべてのソースを-Werrorでコンパイルする必要がある場合がありますが、特定のファイルには、特定の種類の警告を許可する例外がある場合があります。または、プロジェクトで診断を選択的に有効にし、定義されているプリプロセッサマクロに応じてエラーとして処理する場合があります。

PSS。コンパイラは、コードのチャンクに変数が初期化されていないことを認識しています。それが何であれstatic C/C++ analysis(たとえば、無料でcppcheck)、問題のある場所を示します。

于 2012-10-20T20:34:41.973 に答える
1

2 番目のケースで警告 (-Wall) をオンにすると、次のようになります。

foo.cpp:15:8: warning: 'i' may be used uninitialized in this function [-Wuninitialized]

初期化を飛び越すのはエラーですが、コンパイラは初期化されていない変数についてあなたを推測しようとしません。

于 2012-10-20T20:15:26.467 に答える