admin管理员组

文章数量:1391850

I have a file written in C with the format "header.h", and I want to read it using CGO to automatically retrieve the field names defined in header.h.

Here is a shortened example where I include the contents of header.h directly in t.go.

t.go

package main
// #pragma pack(push, 1)
// typedef struct {
//     char tag;
//     short id;
// } header;
// #pragma pack(pop)
import "C"
import ( "fmt"; "unsafe")
func main() {
    value := [8]byte{1,2,3,4,5,6,7,8}
    goHeader := (*C.header)(unsafe.Pointer(&value))
    fmt.Printf("sizeof=%d tag=%d id=%d %+v\n",
    C.sizeof_header,
    goHeader.tag,
    3, // goHeader.id // if I use this it cause id not defined
    goHeader)
}

result compiled by go 1.24.1

sizeof=3 tag=1 id=3 &{tag:1 _:[2 3]}

expect result

sizeof=3 tag=1 id=770 &{tag:1 id:770}

As I know the reason of this behavior is the mismatch alignment between C & Go, but what's better method instead of manual rewrite every field name?

I have a file written in C with the format "header.h", and I want to read it using CGO to automatically retrieve the field names defined in header.h.

Here is a shortened example where I include the contents of header.h directly in t.go.

t.go

package main
// #pragma pack(push, 1)
// typedef struct {
//     char tag;
//     short id;
// } header;
// #pragma pack(pop)
import "C"
import ( "fmt"; "unsafe")
func main() {
    value := [8]byte{1,2,3,4,5,6,7,8}
    goHeader := (*C.header)(unsafe.Pointer(&value))
    fmt.Printf("sizeof=%d tag=%d id=%d %+v\n",
    C.sizeof_header,
    goHeader.tag,
    3, // goHeader.id // if I use this it cause id not defined
    goHeader)
}

result compiled by go 1.24.1

sizeof=3 tag=1 id=3 &{tag:1 _:[2 3]}

expect result

sizeof=3 tag=1 id=770 &{tag:1 id:770}

As I know the reason of this behavior is the mismatch alignment between C & Go, but what's better method instead of manual rewrite every field name?

Share Improve this question asked Mar 12 at 9:08 Daniel YC LinDaniel YC Lin 16.1k18 gold badges69 silver badges104 bronze badges 1
  • A better method is a "setter" function or functions which would take values of the types matching those of the target struct fields and use something like encoding/binary to serialize those values to bytes. Another approach is to have "mirror" Go stuct types and methods/functions which would encode values of those types to bytes. cgo does not support "packing" control, so there's no other portable way of doing what you're after. – kostix Commented Mar 12 at 14:10
Add a comment  | 

1 Answer 1

Reset to default 2

According to the Go Wiki: cgo:

Common Pitfalls: Struct Alignment Issues

As Go doesn’t support packed struct (e.g., structs where maximum alignment is 1 byte), you can’t use packed C struct in Go. Even if your program passes compilation, it won’t do what you want. To use it, you have to read/write the struct as byte array/slice.

So, either align the fields so that Go can deal with it:

package main

// typedef struct {
//     char tag;
//     short id;
// } header;
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {
    value := [8]byte{1, 0, 2, 3}
    goHeader := (*C.header)(unsafe.Pointer(&value))
    fmt.Printf("sizeof=%d tag=%d id=%d %+v\n",
        C.sizeof_header,
        goHeader.tag,
        goHeader.id,
        goHeader)
}

Gives sizeof=4 tag=1 id=770 &{tag:1 id:770}, or use the byte array.

本文标签: cgoHow to process mismatch C amp Go structure issue when Go process C written file formatStack Overflow