LoginSignup
11
10

More than 5 years have passed since last update.

可変長構造体をmalloc()使わないで確保

Posted at

ふつう定数引数で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に初期化している

ローカル宣言に構造体タグ名など不要ってことでこれでも十分。

11
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10