GoとCの間のポインタ渡し
Go言語とC言語の間でポインタを渡す際には、cgo
パッケージが提供する機能を利用します。具体的には、GoのポインタをCの関数に渡すことが可能です。
package main
/*
#include <stdio.h>
void printNum(int *num) {
printf("%d\n", *num);
}
*/
import "C"
import "unsafe"
func main() {
var num int = 10
C.printNum((*C.int)(unsafe.Pointer(&num)))
}
上記のコードでは、Goの変数num
のアドレスをunsafe.Pointer
を通じてCのint
ポインタに変換し、Cの関数printNum
に渡しています。
ただし、この方法には注意点があります。GoのガベージコレクタはCのポインタを認識できないため、Cの関数がGoのポインタを保持している間にGoのガベージコレクタによってメモリが解放されてしまう可能性があります。そのため、GoのポインタをCに渡す際には、そのポインタが有効であることを保証する必要があります。これには、runtime.KeepAlive
関数を使用します。
package main
/*
#include <stdio.h>
void printNum(int *num) {
printf("%d\n", *num);
}
*/
import "C"
import (
"runtime"
"unsafe"
)
func main() {
num := 10
C.printNum((*C.int)(unsafe.Pointer(&num)))
runtime.KeepAlive(num)
}
上記のコードでは、runtime.KeepAlive(num)
を呼び出すことで、num
がガベージコレクタによって回収されないようにしています。これにより、printNum
関数がnum
を安全に参照できることが保証されます。このように、GoとCの間でポインタを渡す際には、メモリ管理に注意が必要です。
GoのポインタをCで扱う場合
GoのポインタをCで扱う場合も、cgo
パッケージが提供する機能を利用します。具体的には、Cの関数にGoのポインタを渡し、そのポインタを通じてGoのメモリを直接操作することが可能です。
package main
/*
#include <stdio.h>
void addNum(int *num) {
(*num)++;
}
*/
import "C"
import "unsafe"
func main() {
var num int = 10
C.addNum((*C.int)(unsafe.Pointer(&num)))
println(num) // 11
}
上記のコードでは、Goの変数num
のアドレスをunsafe.Pointer
を通じてCのint
ポインタに変換し、Cの関数addNum
に渡しています。addNum
関数は、渡されたポインタが指す値をインクリメントします。その結果、Goの変数num
の値が変更されます。
ただし、この方法には注意点があります。GoのガベージコレクタはCのポインタを認識できないため、Cの関数がGoのポインタを保持している間にGoのガベージコレクタによってメモリが解放されてしまう可能性があります。そのため、GoのポインタをCに渡す際には、そのポインタが有効であることを保証する必要があります。これには、runtime.KeepAlive
関数を使用します。
package main
/*
#include <stdio.h>
void addNum(int *num) {
(*num)++;
}
*/
import "C"
import (
"runtime"
"unsafe"
)
func main() {
num := 10
C.addNum((*C.int)(unsafe.Pointer(&num)))
runtime.KeepAlive(num)
println(num) // 11
}
上記のコードでは、runtime.KeepAlive(num)
を呼び出すことで、num
がガベージコレクタによって回収されないようにしています。これにより、addNum
関数がnum
を安全に参照できることが保証されます。このように、GoとCの間でポインタを渡す際には、メモリ管理に注意が必要です。このテーマについては、次の小見出しで詳しく説明します。
unsafe.Pointerによるポインタの渡し
Go言語では、unsafe.Pointer
を使用して任意の型のポインタを別の型のポインタに変換することができます。これにより、GoのポインタをCの関数に渡すことが可能になります。
package main
/*
#include <stdio.h>
void printFloat(float *num) {
printf("%f\n", *num);
}
*/
import "C"
import "unsafe"
func main() {
var num float32 = 1.23
C.printFloat((*C.float)(unsafe.Pointer(&num)))
}
上記のコードでは、Goの変数num
のアドレスをunsafe.Pointer
を通じてCのfloat
ポインタに変換し、Cの関数printFloat
に渡しています。
ただし、unsafe.Pointer
を使用する際には注意が必要です。unsafe.Pointer
はその名の通り、安全ではない操作を可能にするためのものです。そのため、unsafe.Pointer
を使用することで、型安全性を破る可能性があります。また、GoのガベージコレクタはCのポインタを認識できないため、Cの関数がGoのポインタを保持している間にGoのガベージコレクタによってメモリが解放されてしまう可能性があります。
そのため、unsafe.Pointer
を使用する際には、そのポインタが有効であることを保証する必要があります。これには、runtime.KeepAlive
関数を使用します。
package main
/*
#include <stdio.h>
void printFloat(float *num) {
printf("%f\n", *num);
}
*/
import "C"
import (
"runtime"
"unsafe"
)
func main() {
num := float32(1.23)
C.printFloat((*C.float)(unsafe.Pointer(&num)))
runtime.KeepAlive(num)
}
上記のコードでは、runtime.KeepAlive(num)
を呼び出すことで、num
がガベージコレクタによって回収されないようにしています。これにより、printFloat
関数がnum
を安全に参照できることが保証されます。このように、unsafe.Pointer
を使用する際には、メモリ管理に注意が必要です。このテーマについては、次の小見出しで詳しく説明します。
uintptrを用いたポインタの渡し
Go言語では、uintptr
型を使用して任意の型のポインタを整数値に変換することができます。これにより、GoのポインタをCの関数に渡すことが可能になります。
package main
/*
#include <stdio.h>
void printAddr(uintptr_t addr) {
printf("%p\n", (void *)addr);
}
*/
import "C"
import "unsafe"
func main() {
var num int = 10
C.printAddr((C.uintptr_t)(unsafe.Pointer(&num)))
}
上記のコードでは、Goの変数num
のアドレスをunsafe.Pointer
を通じてuintptr
に変換し、Cの関数printAddr
に渡しています。
ただし、uintptr
を使用する際には注意が必要です。uintptr
はその名の通り、ポインタの値を整数値として扱うためのものです。そのため、uintptr
を使用することで、型安全性を破る可能性があります。また、GoのガベージコレクタはCのポインタを認識できないため、Cの関数がGoのポインタを保持している間にGoのガベージコレクタによってメモリが解放されてしまう可能性があります。
そのため、uintptr
を使用する際には、そのポインタが有効であることを保証する必要があります。これには、runtime.KeepAlive
関数を使用します。
package main
/*
#include <stdio.h>
void printAddr(uintptr_t addr) {
printf("%p\n", (void *)addr);
}
*/
import "C"
import (
"runtime"
"unsafe"
)
func main() {
num := 10
C.printAddr((C.uintptr_t)(unsafe.Pointer(&num)))
runtime.KeepAlive(num)
}
上記のコードでは、runtime.KeepAlive(num)
を呼び出すことで、num
がガベージコレクタによって回収されないようにしています。これにより、printAddr
関数がnum
を安全に参照できることが保証されます。このように、uintptr
を使用する際には、メモリ管理に注意が必要です。このテーマについては、次の小見出しで詳しく説明します。
Goのバイト列をCで扱う
Go言語では、[]byte
型を使用してバイト列を表現します。このバイト列をCの関数に渡すことも可能です。
package main
/*
#include <stdio.h>
void printBytes(char* bytes, int len) {
for (int i = 0; i < len; i++) {
printf("%02x ", (unsigned char)bytes[i]);
}
printf("\n");
}
*/
import "C"
import "unsafe"
func main() {
bytes := []byte{0x01, 0x02, 0x03, 0x04, 0x05}
C.printBytes((*C.char)(unsafe.Pointer(&bytes[0])), C.int(len(bytes)))
}
上記のコードでは、Goのバイト列bytes
の先頭要素のアドレスをunsafe.Pointer
を通じてCのchar
ポインタに変換し、Cの関数printBytes
に渡しています。printBytes
関数は、渡されたポインタが指すバイト列を16進数で出力します。
ただし、この方法には注意点があります。GoのガベージコレクタはCのポインタを認識できないため、Cの関数がGoのポインタを保持している間にGoのガベージコレクタによってメモリが解放されてしまう可能性があります。そのため、GoのポインタをCに渡す際には、そのポインタが有効であることを保証する必要があります。これには、runtime.KeepAlive
関数を使用します。
package main
/*
#include <stdio.h>
void printBytes(char* bytes, int len) {
for (int i = 0; i < len; i++) {
printf("%02x ", (unsigned char)bytes[i]);
}
printf("\n");
}
*/
import "C"
import (
"runtime"
"unsafe"
)
func main() {
bytes := []byte{0x01, 0x02, 0x03, 0x04, 0x05}
C.printBytes((*C.char)(unsafe.Pointer(&bytes[0])), C.int(len(bytes)))
runtime.KeepAlive(bytes)
}
上記のコードでは、runtime.KeepAlive(bytes)
を呼び出すことで、bytes
がガベージコレクタによって回収されないようにしています。これにより、printBytes
関数がbytes
を安全に参照できることが保証されます。このように、GoとCの間でポインタを渡す際には、メモリ管理に注意が必要です。このテーマについては、次の小見出しで詳しく説明します。
CのポインタをGoで扱う
C言語から返されたポインタをGoで扱う場合も、cgo
パッケージが提供する機能を利用します。具体的には、Cの関数から返されたポインタをGoのポインタに変換し、そのポインタを通じてCのメモリを直接操作することが可能です。
package main
/*
#include <stdlib.h>
int* createNum() {
int* num = (int*)malloc(sizeof(int));
*num = 10;
return num;
}
*/
import "C"
import "unsafe"
func main() {
numPtr := C.createNum()
num := *(*int)(unsafe.Pointer(numPtr))
println(num) // 10
C.free(unsafe.Pointer(numPtr))
}
上記のコードでは、Cの関数createNum
から返されたポインタをunsafe.Pointer
を通じてGoのint
ポインタに変換し、そのポインタが指す値を取得しています。
ただし、この方法には注意点があります。Cの関数から返されたポインタは、Cのメモリ空間を指しています。そのため、そのポインタを使用し終えたら、必ずfree
関数を呼び出してメモリを解放する必要があります。これを怠ると、メモリリークが発生する可能性があります。
また、Cの関数から返されたポインタをGoで扱う際には、そのポインタが有効であることを保証する必要があります。これには、runtime.KeepAlive
関数を使用します。
package main
/*
#include <stdlib.h>
int* createNum() {
int* num = (int*)malloc(sizeof(int));
*num = 10;
return num;
}
*/
import "C"
import (
"runtime"
"unsafe"
)
func main() {
numPtr := C.createNum()
num := *(*int)(unsafe.Pointer(numPtr))
println(num) // 10
runtime.KeepAlive(numPtr)
C.free(unsafe.Pointer(numPtr))
}
上記のコードでは、runtime.KeepAlive(numPtr)
を呼び出すことで、numPtr
がガベージコレクタによって回収されないようにしています。これにより、numPtr
を安全に参照できることが保証されます。このように、CのポインタをGoで扱う際には、メモリ管理に注意が必要です。