28

GCC は可変長配列 (VLA) をどのように実装しますか? そのような配列は、本質的に alloca によって返されるような、動的に割り当てられたストレージへのポインターですか?

私が考えることができる他の選択肢は、そのような配列が関数の最後の変数として割り当てられ、変数のオフセットがコンパイル時にわかるようにすることです。ただし、2 番目の VLA のオフセットは、コンパイル時に再びわかりません。

4

2 に答える 2

10

VLAサポートのいくつかのGCCドキュメントから取られた次の例の行の割り当てコード(x86 - x64コードも同様)です:

char str[strlen (s1) + strlen (s2) + 1];

の計算strlen (s1) + strlen (s2) + 1eax次のとおりです (GCC MinGW 4.8.1 - 最適化なし):

mov edx, eax
sub edx, 1
mov DWORD PTR [ebp-12], edx
mov edx, 16
sub edx, 1
add eax, edx
mov ecx, 16
mov edx, 0
div ecx
imul    eax, eax, 16
call    ___chkstk_ms
sub esp, eax
lea eax, [esp+8]
add eax, 0
mov DWORD PTR [ebp-16], eax

したがって、本質的にはそうalloca()です。

于 2014-01-17T09:49:01.383 に答える
9

これらは、VLA に関する制限に基づいた、闇の中でのほんの数例にすぎませんが、いずれにせよ:

VLA を次のようにすることはできません。

  • 外部
  • 構造体のメンバー
  • 静的
  • 境界が指定されていない宣言 (関数プロトタイプ用に保存)

これはすべて、VLAがヒープではなくスタックに割り当てられていることを示しています。そうです、VLAはおそらく、新しいブロックが割り当てられるたびに割り当てられるスタックメモリの最後のチャンクです(ブロックスコープ内のブロック、これらはループ、関数、分岐などです)。
これが、VLA が場合によってはスタック オーバーフローのリスクを大幅に高める理由でもあります (警告の言葉: たとえば、VLA を再帰的な関数呼び出しと組み合わせて使用​​することは考えないでください!)。
これが、境界外アクセスが問題を引き起こす可能性が非常に高い理由でもあります。ブロックが終了すると、VLA メモリであったものを指すものすべて、無効なメモリを指します。
しかし、プラス面では: これが、これらの配列がスレッド セーフである理由でもあり (スレッドが独自のスタックを持っているため)、ヒープ メモリと比較して高速である理由でもあります。

VLA のサイズを次のようにすることはできません。

  • extern値_
  • ゼロまたは負

extern 制限は、非ゼロ、非負の制限と同様に自明です...ただし、たとえば、VLA のサイズを指定する変数が signed int の場合、コンパイラはエラーを生成しません。 : VLA の評価と割り当ては、コンパイル時ではなく実行時に行われます。したがって、VLA のサイズは、コンパイル時に指定することはできず、指定する必要もありません
MichaelBurr が正しく指摘したように、VLA はallocaメモリに非常に似ていますが、IMHO の決定的な違いが 1 つallocaあります。VLA はブロック スコープであるため、VLA が使用されているブロックを終了するとメモリが解放されます。

void alloca_diff( void )
{
    char *alloca_c, *vla_c;
    for (int i=1;i<10;++i)
    {
        char *alloca_mem = alloca(i*sizeof(*alloca_mem));
        alloca_c = alloca_mem;//valid
        char vla_arr[i];
        vla_c = vla_arr;//invalid
    }//end of scope, VLA memory is freed
    printf("alloca: %c\n", *alloca_c);//fine
    printf("vla: %c\n\", *vla_c);//undefined behaviour... avoid!
}//end of function alloca memory is freed, irrespective of block scope
于 2014-01-17T09:53:04.437 に答える