one way using cgo: you may access any fields of C struct, using var s *C.struct_tagA = &C.N or simply using s := &C.N like this working sample code:
package main
/*
#include <string.h>
#include <stdint.h>
typedef struct tagA {
int64_t a;
int64_t b;
char c[1024];
}A;
A N={12,22,"test"};
*/
import "C"
import "fmt"
type A struct {
a int64
b int64
c [1024]byte
}
func main() {
s := &C.N // var s *C.struct_tagA = &C.N
t := A{a: int64(s.a), b: int64(s.b)}
length := 0
for i, v := range s.c {
t.c[i] = byte(v)
if v == 0 {
length = i
break
}
}
fmt.Println("len(s.c):", len(s.c)) // 1024
str := string(t.c[0:length])
fmt.Printf("len:%d %q \n", len(str), str) // len:4 "test"
s.a *= 10
fmt.Println(s.a) // 120
}
output:
len(s.c): 1024
len:4 "test"
120
you may use s.a , s.b and s.c directly in Golang. you do not need to copy all of it.
one way using cgo: you may access any fields of C struct, using var s *C.struct_tagA = &C.N or simply using s := &C.N like this working sample code:
package main
/*
#include <string.h>
#include <stdint.h>
typedef struct tagA {
int64_t a;
int64_t b;
char c[1024];
}A;
A N={12,22,"test"};
*/
import "C"
import "fmt"
type A struct {
a int64
b int64
c [1024]byte
}
func main() {
s := &C.N // var s *C.struct_tagA = &C.N
t := A{a: int64(s.a), b: int64(s.b)}
length := 0
for i, v := range s.c {
t.c[i] = byte(v)
if v == 0 {
length = i
break
}
}
fmt.Println("len(s.c):", len(s.c)) // 1024
str := string(t.c[0:length])
fmt.Printf("len:%d %q \n", len(str), str) // len:4 "test"
s.a *= 10
fmt.Println(s.a) // 120
}
output:
len(s.c): 1024
len:4 "test"
120
you may use s.a , s.b and s.c directly in Golang. you do not need to copy all of it.
You can declare variable of struct type in Golang reference to struct C by C.struct_YourStruct
go - golang struct with C struct in CGO - Stack Overflow
cgo - Pass struct and array of structs to C function from Go - Stack Overflow
"casting" the raw bytes of a C-struct into a Go struct
cgo - Good or recommended way to translate C struct to Go struct - Stack Overflow
The problem is that Foo and _Ctype_Foo are different structures.
I would guess you are running on 64 bit. Note that int is 64 bit in go, but is quite likely to be 32 bit in C.
If I change the definition of Foo to this then it works on my machine (64 bit linux)
type Foo struct {
A int32
B int32
}
However I would say that is a recipe for trouble - make your Go and C code use the same structure with
type Foo _Ctype_Foo
I know this is a fairly old topic but I stumbled across it. Here's a modified (correct) version with some additional manipulation from C land on the Go structs.
package main
/*
#include <stdio.h>
typedef struct {
int a;
int b;
} Foo;
void pass_struct(Foo *in) { printf("%d : %d\n", in->a, in->b); }
void pass_array(Foo **in, int len) {
for(int i = 0; i < len; i++) {
pass_struct(in[i]);
in[i]->a += 1;
in[i]->b += 1;
}
}
*/
import "C"
import (
"fmt"
"unsafe"
)
type Foo struct{ a, b int32 }
func main() {
foo := Foo{10, 20}
foos := []*Foo{&Foo{1, 2}, &Foo{3, 4}}
fmt.Println("from C land")
C.pass_struct((*C.Foo)(unsafe.Pointer(&foo)))
C.pass_array((**C.Foo)(unsafe.Pointer(&foos[0])), C.int(len(foos)))
fmt.Println("a & b should have incremented with 1")
fmt.Println("from Go land")
for _, foo := range foos {
fmt.Printf("%d : %d\n", foo.a, foo.b)
}
}
Output:
from C land
10 : 20
1 : 2
3 : 4
a & b should have incremented with 1
from Go land
2 : 3
4 : 5
Hi all,
New gopher here. I am writing the server side of a client/server application. Previous server was using Python, specifically the ctypes module, to convert the received data from the C client into the Python equivalent. The C struct looks something like this:
#pragma pack(1)
typedef struct _DATA {
uint32_t ID;
uint32_t NameLen;
wchar_t Name[]; // Variable, depends on NameLen.
} DATA;
In Python I would receive the raw bytes from the network, and "cast" them into the appropriate equivalent using ctypes. I know Go has cgo, and I've read this article, but it's not exactly my use case and I'm kind of stuck.
Essentially I want to read the raw bytes of the C struct from the network, convert them to the Go equivalent, parse/handle them, then reverse the process.
I'm fairly certain what I'm trying to do is possible in Go, but I'm pretty new to it and unfamiliar with what I should be looking into. Using a different format like JSON, etc. is not at option due to overhead and not controlling the client.
Thanks!
You can use C structs in Go (though if the struct holds a union it gets a bit more complex). The simplest way would just be
type Cons struct {
c C.cons_t
}
Any function in C is now just a passthrough in Go
func Parse(s string) Cons {
str := C.CString(s)
// Warning: don't free this if this is stored in the C code
defer C.free(unsafe.Pointer(str))
return Cons{c: C.parse(str)}
}
This has its own overhead, since you have to do a type conversion on element access. So what was before var c Cons{}; c.Type is now
func (c Cons) Type() int {
return int(c.c.type)
}
An intermediate compromise can be used where you store fields alongside the C type for easy access
type Cons struct {
type int
c C.cons_t
}
func (c *Cons) SetType(t int) {
c.type = t
c.c.type = C.size_t(t)
}
func (c Cons) Type() int {
return c.type
}
The only real problem with this is that if you're calling C functions a lot, this can introduce maintenance overhead in setting the Go-side fields:
func (c *Cons) SomeFuncThatAltersType() {
C.someFuncThatAltersType(&c.c)
c.Type = int(c.c.type) // now we have to remember to do this
}
I would recommend against the accessor functions. You should be able to access the fields of the C struct directly, which will avoid the Go -> C function call overhead (which is non-trivial). So you might use something like:
func TranslateCCons2GoCons (c *C.cons_t) *Cons {
if c == nil {
return nil
}
return &Cons{
type: int(c.type),
car: TranslateCCons2GoCons(c.car),
cdr: TranslateCCons2GoCons(c.cdr),
}
}
Also, if you allocate a C string with C.CString, you need to free it. So your Parse function should look something like:
func Parse (str string) *Cons {
str_ptr := C.CString(str)
defer C.free(unsafe.Pointer(str_ptr)
cons_ptr := C.parse(str_ptr)
retCons := TranslateCCons2GoCons(cons_ptr)
// FIXME: Do something to free cons_ptr here. The Go runtime won't do it for you
return retCons
}
You can use the unsafe package to cast the data. The Go compiler can no longer check the types here, so it's up to you to ensure that the size and type of everything is identical between C.struct_hash and Hash.
Chash := *(*C.struct_hash)(unsafe.Pointer(&hash))
consider the align in c you can not simply do the cast. the best way should be assign value 1 by 1 from c to go or go to c. But this process is painful is the struct is large and struct contain struct