GCC は可変長配列 (VLA) をどのように実装しますか? そのような配列は、本質的に alloca によって返されるような、動的に割り当てられたストレージへのポインターですか?
私が考えることができる他の選択肢は、そのような配列が関数の最後の変数として割り当てられ、変数のオフセットがコンパイル時にわかるようにすることです。ただし、2 番目の VLA のオフセットは、コンパイル時に再びわかりません。
GCC は可変長配列 (VLA) をどのように実装しますか? そのような配列は、本質的に alloca によって返されるような、動的に割り当てられたストレージへのポインターですか?
私が考えることができる他の選択肢は、そのような配列が関数の最後の変数として割り当てられ、変数のオフセットがコンパイル時にわかるようにすることです。ただし、2 番目の VLA のオフセットは、コンパイル時に再びわかりません。
VLAサポートのいくつかのGCCドキュメントから取られた次の例の行の割り当てコード(x86 - x64コードも同様)です:
char str[strlen (s1) + strlen (s2) + 1];
の計算strlen (s1) + strlen (s2) + 1
はeax
次のとおりです (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()
です。
これらは、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