runtime.SetFinalizer:无法确定 C.Char 的名称类型

请考虑以下示例代码:


package main


/*

#include <stdio.h>

#include <stdlib.h>

*/

import "C"



import (

    "fmt"

    "runtime"

    "unsafe"

)


func main() {

    // Convert Go string to C string using C.CString

    cString := C.CString("Wold!")

    fmt.Printf("C.CString type: %T\n", cString)

    //C.free(unsafe.Pointer(cString)) // <-- this works, but I don't want to free it manually..


    runtime.SetFinalizer(&cString, func(t *C.Char) {

        C.free(unsafe.Pointer(t))

    })

}

我正在试验 cGo,并试图释放cString. 当我尝试释放我的变量 cString 时,runtime.SetFinalizer我遇到了:


$ go build a.go 

# command-line-arguments

./a.go:22:41: could not determine kind of name for C.Char

请指出正确的方向。谢谢!


Smart猫小萌
浏览 225回答 1
1回答

精慕HU

当 cgo 系统将你的包装器变成 Go 编译器可以理解的东西时,它必须将每个 C 类型转换为 Go 类型以用于各种目的。事实证明这不适用于您的情况(这是您看到的错误)。这实际上没关系,因为您的代码一开始就不会按照您想要的方式工作。当 Go 的垃圾收集器准备好释放占用 Go 内存的 Go 对象但返回一个不是C.CstringGo 内存的指针时,运行时终结器就会运行。特别要注意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 (&nbsp; &nbsp; &nbsp; &nbsp; "fmt"&nbsp; &nbsp; &nbsp; &nbsp; "runtime"&nbsp; &nbsp; &nbsp; &nbsp; "time"&nbsp; &nbsp; &nbsp; &nbsp; "unsafe")type S struct {&nbsp; &nbsp; &nbsp; &nbsp; Foo&nbsp; &nbsp; int&nbsp; &nbsp; &nbsp; &nbsp; ToFree unsafe.Pointer}func main() {&nbsp; &nbsp; &nbsp; &nbsp; doit()&nbsp; &nbsp; &nbsp; &nbsp; runtime.GC()&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(10 * time.Millisecond) // ugly hack}func doit() {&nbsp; &nbsp; &nbsp; &nbsp; cString := C.CString("Wold!")&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("C.CString type: %T\n", cString)&nbsp; &nbsp; &nbsp; &nbsp; x := &S{Foo: 1, ToFree: unsafe.Pointer(cString)}&nbsp; &nbsp; &nbsp; &nbsp; runtime.SetFinalizer(x, func(t *S) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("freeing C string")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; C.free(t.ToFree)&nbsp; &nbsp; &nbsp; &nbsp; })}当分配的对象x超出范围时,它就有资格进行 GC。实际的 GC 可能永远不会发生,所以我强制使用runtime.GC()in 进行main。这会触发终结器:$ ./cfree_exampleC.CString type: *main._Ctype_charfreeing C string“丑陋的黑客”就在那里,因为如果main在终结器调用完成写入freeing C string消息之前返回,它就会丢失。在一个真正的程序中你不需要这个。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go