简体   繁体   中英

Determine with reflect if struct field is incomplete Cgo type

I have some generic code that uses reflection to handle struct fields. These fields may or may not include C types, referenced through Cgo.

One problem I encountered was that those aforementioned C types may be "incomplete structs", for instance: typedef struct unknown u; . This can result in a panic later on in the code.

I ideally need to be able to check for and skip instances like this, without accidentally skipping valid fields.

I thought about checking if the value returned by Type.Size() is 0, but empty Go structs will return the same.

Is there a way to do this?

TL;DR summary: Cgo doesn't have incomplete types, so there's nothing to test for here; but you should not be using incomplete types in a way that causes a runtime panic. (Show a minimal reproducible example and someone can probably show you where you have gone wrong.)


In C, you cannot have an object of incomplete type, but you can have a value of type pointer to (some incomplete type), which you can store in an object of type pointer to the incomplete type. It's not possible to follow (dereference) the pointer.

Oddly, Cgo seems to allow following the pointer. Probably this is because there is no such thing as an incomplete type in Go, so Cgo merely turns the C object into a structure containing no fields and having zero size:

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())
}

I have some generic code that uses reflection to handle struct fields. These fields may or may not include C types, referenced through Cgo. ... This can result in a panic later on in the code.

Given the above (that the incomplete "object" itself has size zero), never embed an actual incomplete-type Cgo type into a Go type. Always use a (C) pointer. Otherwise any subsequent fields in the Go type will overlay the actual fields in the C code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM