多くの人から、C99で導入された可変長配列はひどいという話を聞きました。IRCの何人かの人は1分前に言った«C++がVLAを取得するとは思わない、strousoupはそれらについていくつかの非常に否定的なコメントをした»。
それらの人々がVLAを嫌う理由は何ですか?
多くの人から、C99で導入された可変長配列はひどいという話を聞きました。IRCの何人かの人は1分前に言った«C++がVLAを取得するとは思わない、strousoupはそれらについていくつかの非常に否定的なコメントをした»。
それらの人々がVLAを嫌う理由は何ですか?
VLAは、実行時にスタックにアレイを割り当てるため、コンパイル時に使用されるスタックサイズを決定するのが難しくなるか、不可能になります。スタックには(ヒープと比較して)使用可能なメモリがかなり少ないため、多くの人がVLAがスタックオーバーフローの大きな可能性を秘めていることを心配しています。
MISRA-Cコーディング標準の次のバージョンでは、VLAも禁止される可能性があります。
可変長配列には問題がありますが、それらがどのようになったかを覚えておく必要があります。の代わりとしてalloca()
、これは間違いなくさらに問題があります。
PDP-11に実装するのは簡単でしたが、他のアーキテクチャには当てはまらず、RitchieとThompsonはPDP-11を実装から削除しました。
ただし、可変サイズの自動割り当てはalloca()
、問題があるにもかかわらず復活するのに十分有用だったようです(特に、任意の関数呼び出しが可能な場所では使用できず、多くのアーキテクチャでは、とにかくコンパイラが組み込まれている必要があります)。Cワーキンググループは、そのような機能を提供することに同意しましたが、可変長配列が優れたソリューションであると考えました。
C99で追加された機能(複素数、型-一般的な数学、、restrict
...)を見ると、それらの多くがCを数値計算のためのより良い言語にすることを目的としていることに気付くはずです。可変長配列はそこでも有用であり、Fortranはその時点ですでにそれらを持っていたと思います。さらに、それらの導入により、可変的に変更された派生型(たとえば、可変サイズの配列へのポインター)も作成されました。これは、行列を処理するときに特に役立ちます。
他の人が指摘しているように、VLAを使用すると、スタックフレームを簡単にオーバーフローさせることができます。私はコンパイラーのライターではありませんが、VLAはサポートするのにバガーになる可能性があることを理解しています(C2011ではオプションになっています)。そして、それらの使用はブロックまたは関数スコープに制限されています。ファイルスコープでVLAを使用することはできません。また、VLAに外部リンクを設定することもできません。
ただし、VLA構文がなくなるのは見たくありません。次のように、実行時まで内部の次元がわからない多次元配列を動的に割り当てる場合に非常に便利です。
size_t r, c;
// get values for r and c
int (*arr)[c] = malloc(r * sizeof *arr);
if (arr)
{
...
arr[i][j] = ...;
...
free(arr);
}
1つの連続した割り当て(および1つの対応するfree
)、および2D配列として添え字を付けることができます。代替案は通常、断片的な割り当てを意味します。
size_t r, c;
...
int **arr = malloc(sizeof *arr * r);
if (arr)
{
for (i = 0; i < c; i++)
arr[i] = malloc(sizeof *arr[i] * c);
...
arr[i][j] = ...;
...
for (i = 0; i < c; i++)
free(arr[i]);
free(arr);
}
または1-dオフセットを使用します。
int *arr = malloc(sizeof *arr * r * c);
if (arr)
{
...
arr[i * r + j] = ...;
...
free(arr);
}
VLAを使用すると、スタックのオーバーフローがはるかに簡単になります。VLAを使用するほとんどの場所では、関数パラメーターの1つに基づいて長さを決定します。パラメータが予期しないものである場合、スタックに非常に大きな配列を割り当てることになる可能性があります。引数の組み合わせによってスタックがオーバーフローする可能性がないことが確実でない限り、動的割り当てを使用する必要があります。
組み込みプログラミングを行う場合、スタックオーバーフローが発生しないようにメモリ使用量を十分に追跡する可能性が高い数少ない状況の1つであるため、これらを使用するのが理にかなっている場所の1つは組み込みプラットフォームです。 。