Когда система cgo превращает вашу оболочку в то, что понимает Go компилятор, она должна преобразовать каждый из типов C в тип Go для различных целей. Оказывается, в вашем случае это не работает (это ошибка, которую вы видели).
Это действительно нормально, потому что ваш код никогда бы не работал так, как вы изначально хотели. Финализатор времени выполнения запускается, когда сборщик мусора Go готов освободить объект Go, который занимает Go память, но C.Cstring
возвращает указатель, который является не Go памятью. В частности, обратите внимание на следующую цитату из документации cgo :
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
Поскольку возвращенная строка находится в куче «C "он никогда не будет завершен сборщиком мусора Go. Если бы ваш код был скомпилирован, он бы просто не работал.
Если у вас есть объект Go, время жизни которого совпадает со временем жизни объекта C, вы, возможно, могли бы его использовать. Вот выдуманный (но работающий) пример:
package main
/*
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"runtime"
"time"
"unsafe"
)
type S struct {
Foo int
ToFree unsafe.Pointer
}
func main() {
doit()
runtime.GC()
time.Sleep(10 * time.Millisecond) // ugly hack
}
func doit() {
cString := C.CString("Wold!")
fmt.Printf("C.CString type: %T\n", cString)
x := &S{Foo: 1, ToFree: unsafe.Pointer(cString)}
runtime.SetFinalizer(x, func(t *S) {
fmt.Println("freeing C string")
C.free(t.ToFree)
})
}
Когда выделенный объект для x
выходит за рамки, он становится подходящим для G C. Фактический G C может никогда не произойти, поэтому я заставил его указать runtime.GC()
в main
. Это запускает финализатор:
$ ./cfree_example
C.CString type: *main._Ctype_char
freeing C string
Здесь присутствует «уродливый взлом», потому что если main
возвращается до того, как вызов финализатора завершит запись сообщений freeing C string
, он будет потерян. В реальной программе вам это не понадобится.