【问题标题】:Determine with reflect if struct field is incomplete Cgo type使用反射确定结构字段是否不完整 Cgo 类型
【发布时间】:2021-05-12 19:43:20
【问题描述】:

我有一些使用反射来处理结构字段的通用代码。这些字段可能包含也可能不包含通过 Cgo 引用的 C 类型。

我遇到的一个问题是前面提到的那些 C 类型可能是“不完整的结构”,例如:typedef struct unknown u;。这可能会导致稍后在代码中出现恐慌。

理想情况下,我需要能够检查和跳过这样的实例,而不会意外跳过有效字段。

我想过检查 Type.Size() 返回的值是否为 0,但空的 Go 结构将返回相同的值。

有没有办法做到这一点?

【问题讨论】:

  • 你不会也跳过 Go 空结构吗?
  • @Adrian 在我的情况下,不一定

标签: go cgo reflect


【解决方案1】:

TL;DR 总结:Cgo 没有不完整的类型,所以这里没有什么要测试的;但是您不应该以导致运行时恐慌的方式使用不完整的类型。 (显示minimal reproducible example,有人可能会告诉你哪里出错了。)


在 C 中,你不能有一个不完整类型的对象,但你可以有一个 pointer to 类型的值(一些不完整的类型),你可以将它存储在 类型的对象中指向不完整类型的指针。无法跟随(取消引用)指针。

奇怪的是,Cgo 似乎允许跟随指针。这可能是因为 Go 中没有不完整类型这样的东西,所以 Cgo 只是将 C 对象变成了一个不包含字段且大小为零的结构:

package main

// #include <stdlib.h>
//
// struct incomp;
// struct incomp *foo() {
//     return malloc(10);
// }
import "C"

import (
        "fmt"
        "reflect"
)

func newFoo() *C.struct_incomp {
        return C.foo()
}

func main() {
        p := newFoo()
        t := reflect.TypeOf(*p)
        if t.Kind() != reflect.Struct {
                panic("not a struct")
        }
        fmt.Println("Size:", t.Size())
        fmt.Println("NumFields:", t.NumField())
}

我有一些使用反射来处理结构字段的通用代码。这些字段可能包括也可能不包括通过 Cgo 引用的 C 类型。 ...这可能会导致稍后在代码中出现恐慌。

鉴于上述情况(不完整的“对象”本身的大小为零),永远不要将实际的不完整类型 Cgo 类型嵌入到 Go 类型中。始终使用 (C) 指针。否则 Go 类型中的任何 后续 字段将覆盖 C 代码中的实际字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多