为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
Smart猫小萌 2022-06-13 15:04:43
请考虑以下示例代码: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请指出正确的方向。谢谢!
查看完整描述

1 回答

?
精慕HU

TA贡献1845条经验 获得超8个赞

当 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 (

        "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超出范围时,它就有资格进行 GC。实际的 GC 可能永远不会发生,所以我强制使用runtime.GC()in 进行main。这会触发终结器:


$ ./cfree_example

C.CString type: *main._Ctype_char

freeing C string

“丑陋的黑客”就在那里,因为如果main在终结器调用完成写入freeing C string消息之前返回,它就会丢失。在一个真正的程序中你不需要这个。


查看完整回答
反对 回复 2022-06-13
  • 1 回答
  • 0 关注
  • 224 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号