4

次の例は、この問題を示しています。

#include <cstdio>

int main()
{
        unsigned int remaining=1;

        goto loop;

        while(remaining) {
                unsigned char tmp[remaining];
                printf("&tmp: %p\n",tmp);
loop:
                remaining = 512;//or something else;
        }
}

最初は、「remaining」変数の初期化に少し時間がgotoかかり、以前は 1 行で初期化していました。ただし、この例では、行にセグメンテーション違反が発生しprintfます。

配列が正しく初期化されていないようです。

gdb でさえ tmp 配列のアドレスを出力できません:

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005b8 in main () at test.cpp:11
11          printf("&tmp: %p\n",tmp);
(gdb) p tmp
$1 = 0xfffffffffffffe00 <error: Cannot access memory at address 0xfffffffffffffe00>

私のgccバージョン:

gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

コンパイル:

g++ -o testc test.cpp

goto を削除するか、可変長配列を固定配列に置き換えると、セグメンテーション違反はなくなります。実際に何が起こっているのですか?

これはgccのバグですか?と可変長配列の組み合わせがgoto許可されていない場合、警告が表示されますか?

4

1 に答える 1

5

可変長配列 ( VLA ) は、gccが C++ の拡張機能としてサポートする C99 の機能であり、C99 では、VLA 宣言を超えるジャンプは未定義の動作です。ドラフト C99 標準セクションから6.8.6.1 goto ステートメント:

goto ステートメントは、可変に変更された型を持つ識別子のスコープ外からその識別子のスコープ内にジャンプしてはなりません。

clanggcc 4.9実際にはこれをエラーにして、次のように言います。

error: goto into protected scope
    goto loop;
    ^

note: jump bypasses initialization of variable length array
            unsigned char tmp[remaining];
                          ^

gcc バグ レポート: Jumps into VLA or VM scope not reject for C++を参照してください。

C++ で自動変数の宣言を飛び越えるためのルールは、セクション6.7 [stmt.dcl]で説明されています。

ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法ではできません。自動保存期間を持つ変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプ87するプログラムは、変数がスカラー型、単純なデフォルト コンストラクターと単純なデストラクタを持つクラス型を持たない限り、形式が正しくありません。これらの型のいずれかの cv 修飾バージョン、または上記の型のいずれかの配列であり、初期化子 (8.5) なしで宣言されています。[ 例:

void f() {
    // ...
    goto lx; // ill-formed: jump into scope of a
ly:
    X a = 1;
    // ...
lx:
    goto ly; // OK, jump implies destructor
             // call for a followed by construction
            // again immediately following label ly
}

—終わりの例]

于 2015-03-18T14:06:47.280 に答える