概要
前回 複数のポインタを配列を管理する方法を紹介しました
今回は更にそれを Struct で管理する方法を紹介します
環境
- macOS 10.14.3
- Ruby 2.5.1p57
サンプルコード
コード全体は以下の通りです
require 'inline'
class MyTest
inline do |builder|
builder.add_compile_flags '-x c++', '-std=c++11'
builder.include '<stdio.h>'
builder.include '<malloc/malloc.h>'
builder.prefix '
typedef struct {
int count;
uint8_t *ary[];
} Data;
'
builder.c_singleton '
VALUE allocate() {
Data *p = ALLOC(Data);
return Data_Wrap_Struct(self, NULL, free, p);
}
'
builder.c %q[
void array_in_array() {
Data *p;
Data_Get_Struct(self, Data, p);
p->count = 3;
uint8_t *buf1 = (uint8_t *)malloc(16 * sizeof(uint8_t));
for (unsigned long i = 0; i < malloc_size(buf1); i++) {
buf1[i] = 'a';
}
p->ary[0] = buf1;
uint8_t *buf2 = (uint8_t *)malloc(16 * sizeof(uint8_t));
for (unsigned long i = 0; i < malloc_size(buf2); i++) {
buf2[i] = 'b';
}
p->ary[1] = buf2;
uint8_t *buf3 = (uint8_t *)malloc(16 * sizeof(uint8_t));
for (unsigned long i = 0; i < malloc_size(buf3); i++) {
buf3[i] = 'c';
}
p->ary[2] = buf3;
}
]
builder.c %q[
void show() {
Data *p;
Data_Get_Struct(self, Data, p);
uint8_t **ary = p->ary;
for (int i = 0; i < p->count; ++i) {
uint8_t *buf = ary[i];
for (int j = 0; j < 16; ++j) {
printf("%c", buf[j]);
}
printf("\n");
}
}
]
end
end
p = MyTest.new
p.array_in_array
p.show
ポイント解説
Struct の定義で可変長配列 uint8_t *ary[];
を定義しておきます
そして C 側で格納したいポインタを生成して格納する際に Data_Get_Struct
で取得したポインタを使って直接配列に格納します
あとは取得する側の関数で uint8_t **ary = p->ary;
として取得し多重配列を扱うようにループさせれば OK です
macOS の場合上記でエラーにならないのですが Linux などの環境だと free(): invalid next size (fast)
が発生する場合があります
その場合は uint8_t **ary;
として Struct 内で配列を参照するポインタを準備すれば OK です
ちなみに macOS でポインタ版にするとぬるぽになります
メモリ空間の扱い方が macOS と Linux だと違うのかもしれません
この辺りは OS を考慮する必要があるので少し面倒になるかもしれません
0 件のコメント:
コメントを投稿