Передача указателей в C
При работе с cgo возникает необходимость передавать указатели на данные из Go в C-функции. Основное правило: Go может передавать указатель на память, выделенную в Go, в C, но при этом Go-рантайм не должен перемещать эту память. Поэтому важно использовать правильные подходы для работы с указателями. В первый параметр передается указатель на данные, во второй - размер данных.
Синтаксис
C.function(&var, C.int(size))
Пример
Рассмотрим базовый пример передачи указателя на Go-переменную в C-функцию:
package main
/*
#include <stdio.h>
void print_int(int *p) {
printf("Value: %d\n", *p);
}
*/
import "C"
func main() {
value := 42
C.print_int(&value)
}
Результат выполнения кода:
"Value: 42"
Пример
Передача указателя на слайс через функцию C.CBytes:
package main
/*
#include <string.h>
#include <stdlib.h>
void process_data(void *data, int size) {
unsigned char *bytes = (unsigned char*)data;
for (int i = 0; i < size; i++) {
bytes[i] += 1;
}
}
*/
import "C"
import "unsafe"
func main() {
data := []byte{1, 2, 3, 4, 5}
cData := C.CBytes(unsafe.Pointer(&data[0]), C.int(len(data)))
defer C.free(cData)
C.process_data(cData, C.int(len(data)))
}
Пример
Передача указателя на структуру в C:
package main
/*
#include <stdlib.h>
typedef struct {
int x;
int y;
} Point;
void move_point(Point *p, int dx, int dy) {
p->x += dx;
p->y += dy;
}
*/
import "C"
func main() {
point := C.Point{x: 10, y: 20}
C.move_point(&point, 5, 10)
}
Важные ограничения
При передаче указателей из Go в C необходимо помнить о следующих правилах:
package main
/*
#include <stdlib.h>
void modify_string(char *s) {
s[0] = 'H';
}
*/
import "C"
import "unsafe"
func main() {
// Правильно: используем C.CString для выделения памяти в C
str := C.CString("hello")
defer C.free(unsafe.Pointer(str))
C.modify_string(str)
// Неправильно: передача указателя на Go-строку
// goStr := "world"
// C.modify_string(&goStr) // ОШИБКА!
}