プログラミング言語 C の新機能 Part XX: ARR#0:可変長配列[さよなら alloca]
(1999/07/19 [月])
ある関数に入る毎に違った大きさが必要になる配列(可変長配列)を、今まではどのように作成していました? その作成方法は、大体次に挙げる方法のどれかでしょう。
(1)あらかじめ最大の配列を作る方法。もし最大の大きさを見積もることができるのであれば、あらかじめその最大の大きさの配列を作ってそれを利用するという方法があります。しかしこの方法では最大が見積もれる時にしか使用することができず、また必ずしもメモリを有効に使用することができません。
(2)malloc を使う方法。必要となる大きさを malloc で確保し、ポインタに割り当てて使うという方法があります。しかし、この方法では、一般的に malloc 関数のオーバヘッドが自動変数の確保より遅くなりがちであるので効率がよくないという問題がありました。また最後に領域を開放するのを忘れがちという問題もありました。
(3)alloca を使う方法。プログラミング言語 C の標準関数ではないのですが、alloca という関数がよく使われていました。この方法では、この関数にいる間有効となるメモリ領域(通常スタック)のメモリを確保し、そのメモリを割り付けるという関数です。もちろんこの場合にはその関数を抜けると領域が自動開放されるので、領域の開放忘れはありません。しかし、alloca は演算子ではなく、単なるライブラリの関数なので、コンパイラが仮定するスタックの使い方に気をつけて使用する必要がありました。例えば、関数の引数の中で使用するとプログラムが正しく動かなくなる可能性がありました。
以上のように可変長な配列を作成するにはいくつかの方法とそれぞれの問題がありましたが、今度の新しい C 言語の機能を使うとこの問題は解決します。
(4)新しい C 言語の機能を使う方法。今度の C 言語では、配列の大きさの指定に数値定数だけではなく、数値変数も使用することができます。そのようなことから、今までの C 言語の表記と整合が取れたまま、かつ簡単に動的に可変長な配列を作成することができるようになります。
(1)あらかじめ最大の配列を作る方法。もし最大の大きさを見積もることができるのであれば、あらかじめその最大の大きさの配列を作ってそれを利用するという方法があります。しかしこの方法では最大が見積もれる時にしか使用することができず、また必ずしもメモリを有効に使用することができません。
(2)malloc を使う方法。必要となる大きさを malloc で確保し、ポインタに割り当てて使うという方法があります。しかし、この方法では、一般的に malloc 関数のオーバヘッドが自動変数の確保より遅くなりがちであるので効率がよくないという問題がありました。また最後に領域を開放するのを忘れがちという問題もありました。
(3)alloca を使う方法。プログラミング言語 C の標準関数ではないのですが、alloca という関数がよく使われていました。この方法では、この関数にいる間有効となるメモリ領域(通常スタック)のメモリを確保し、そのメモリを割り付けるという関数です。もちろんこの場合にはその関数を抜けると領域が自動開放されるので、領域の開放忘れはありません。しかし、alloca は演算子ではなく、単なるライブラリの関数なので、コンパイラが仮定するスタックの使い方に気をつけて使用する必要がありました。例えば、関数の引数の中で使用するとプログラムが正しく動かなくなる可能性がありました。
func(int sz) { //(1)あらかじめ最大の配列を作る方法(ただし sz <= MAXSZ) int buffer[MAXSZ]; //(2)malloc を使う方法 int *buffer; buffer = malloc(sz); free(buffer); //(3)void *alloca(size_t); を使う方法 int *buffer = alloca(sz); //(4)新しい C 言語の機能を使う方法 int buffer[sz]; } |
以上のように可変長な配列を作成するにはいくつかの方法とそれぞれの問題がありましたが、今度の新しい C 言語の機能を使うとこの問題は解決します。
(4)新しい C 言語の機能を使う方法。今度の C 言語では、配列の大きさの指定に数値定数だけではなく、数値変数も使用することができます。そのようなことから、今までの C 言語の表記と整合が取れたまま、かつ簡単に動的に可変長な配列を作成することができるようになります。
by seclan