ふつう定数引数でmalloc()呼ぶのは、
// つまり、長さ256の配列を確保するのに
int int_array[256];
// でなく
int* int_array = (int*)malloc(256);
// なんてやるのは
その配列をスコープ外へreturnする場合くらいです。
ところが、スコープ内で使うだけの配列なのに定数でmalloc()を呼び出さないといけなくて悔しい思いをすることがあります。それを強いてくるのが、可変長構造体。
struct sizable {
size_t length;
int contents[1];
}
なんていう構造を持っていて、contents
配列の長さは1と宣言されているものの実際にはlength
分だけ格納できるようにメモリ確保しておいてねという仕様になっている構造体。Win32 APIでこれがよく出てくるんですわ…。
sizable* s = (sizable*)malloc(sizeof(sizable) + (256-1) * sizeof(int));
s->length = 256;
// s を使ってなんかAPIを呼び出している
free(s);
などという残念なコードを強いられます。ローカルスコープ内で使うためだけに定数引数のmalloc、そしてfree。これが悔しくなければCプログラマじゃない。
可変長構造体を構造体でくるめ
この場合、sizable
変数のうしろにint
255個分のメモリが確保されていればいいのです。ならこんな構造体を用意すれば…?
struct sizable_256 {
sizable base;
int dummy[256 - 1];
};
これならメモリが確保されています。そしたらこう書けばいいと。
struct sizable_256 {
sizable base;
int dummy[256 - 1];
};
sizable_256 s{ sizable { 256 } }; // s.base.length を256に初期化している
// &s.base を使ってなんかAPIを呼び出している
// freeしなくていいよ!
読む人を混乱させてもいいのなら
struct {
sizable base;
int dummy[256 - 1];
} s{ sizable { 256 } }; // s.base.length を256に初期化している
ローカル宣言に構造体タグ名など不要ってことでこれでも十分。