cgoでvoid **(ダブルポインター)を使う
TL;DR;
void **
はどうやって表現する? *unsafe.Pointer
.
void *
は? unsafe.Pointer
.
example
var u8v **C.uint8_t var doubleVoidPointer *unsafe.Pointer u8v = (**C.uint8_t)(C.malloc(size)) doubleVoidPointer = (*unsafe.Pointer)(unsafe.Pointer(u8v)) free(unsafe.Pointer(u8v))
failure example
// `()`をつけ忘れている u8v = (**C.uint8_t)C.malloc(size)
キャスト時にカッコ()
をつけ忘れると、expected ';', found C
といったエラーが出る
Ref
理解できない場合は以下2つの公式ドキュメントを読むと良い ただしここでは翻訳したurlとする
以下ポエム
GCがあることにより困るのは以下の2点
- GCによる変数の格納場所の入れ替え(以降moveとする)
- 未参照時にfreeされる
この2つの特徴を混ぜていて、理解するのに時間がかかった。 そのため明確に分けると良い。
uintptr
uintptrはポインタを格納することのできる大きさを持った整数
unsafe.Pointerはポインタ
- moveによる影響
uintptrが指す先はあくまで整数であるため、moveが発生しても変化しない
(int型の値はgcが発生してもint型の値)
- 未参照時のfree
ただし参照されなくなると、freeされてしまう
uintptr型の数値は解放されないが、uintptrが示すアドレスの先に、Goポインターがあると、解放される
GCはCPointerを勝手に解放しない=GCはCPinterをGC対象としない
CはCのプログラム設計者の意図でメモリ管理されているため、そこにGCが介入すると破綻するため
move時のpointer
move時はアドレスが変わる。
そのためポインターを保持していると、ポインターの書き換えが起こる。
疑問
Cポインターのアドレスが書き換えられると困らない?
こまる。そのためCポインターは書き換えが発生しない(GC管理対象外)。
CポインターをGoポインターに保持する場合は困らない?
例えば以下のような場合
stuct Piyo { int pon } struct Piyo* piyo_open(void) { p = (* struct Piyo)malloc(sizeof(struct Piyo)) p.pon = 0 return p } stuct Fuga { struct Piyo *piyo } struct Fuga* fuga_open(void) { f = (* struct Fuga)malloc(sizeof(struct Fuga)) f.piyo = piyo_open(void) return f }
type Hoge struct { fuga *C.Fuga } func main() { hoge := &Hoge{} hoge.fuga = C.fuga_open() }
hogeはGoPointer GC対象 hoge.fugaはCPointer GC対象外
hogaのアドレスが変わっても、hogeの中身のfugaはGC対象外だから、そのままの値が維持される
つまり困らない
unsafe.Pointer
こちらはあくまでポインター
- GCによる変数の格納場所の入れ替え(move)
- 未参照時にfreeされる
ダブルポインターの要素の参照。後で書く
[]
indexは使えないため、uintptrに変換してアクセスする
struct Hoge { char *x };
for i := 0; i < int(num); i++ { p := *(**C.Hoge)(unsafe.Pointer(uintptr(unsafe.Pointer(xxx)) + uintptr(i)*unsafe.Sizeof(uintptr(0)))) fmt.Println(i, C.GoString(p.x)) }