I've got a C function that fills a C struct:
typedef struct {
char name[8];
}
I need to copy data into Go lang struct that has the same content:
type sData struct {
Name [8]byte
}
The structure has parameters of multiple sizes: 4, 12, 32 so it would be nice to have a function that deals with more than just one size.
thanks
To make this a little more generic, you can decompose the C char array to a *C.char, then use unsafe.Pointer to cast it back to an array.
func charToBytes(dest []byte, src *C.char) {
n := len(dest)
copy(dest, (*(*[1024]byte)(unsafe.Pointer(src)))[:n:n])
}
Or maybe a little easier
func charToBytes(src *C.char, sz int) []byte {
dest := make([]byte, sz)
copy(dest, (*(*[1024]byte)(unsafe.Pointer(src)))[:sz:sz])
return dest
}
Related
I'm using syscall.Syscall(...) to call a C method in a dll.
This is the C method signature:
SENSEI_API HSENSEI SENSEI_open(const char* sensigrafo, const char* options, SENSEI_ERR* se);
This is the SENSEI_ERR struct:
typedef struct
{
int code;
char* error_string;
} SENSEI_ERR;
In my GO program I declared a struct:
type senseiErr struct {
code int
error_string *byte
}
And tried to call the method:
var nargs uintptr = 3
var err senseiErr
ret, _, callErr := syscall.Syscall(uintptr(senseiOpen),
nargs,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("en"))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(""))),
uintptr(unsafe.Pointer(&err)),
)
As you may have guessed, the SENSEI_open method fill the SENSEI_ERR argument with the code and the text of the error.
Now I need to read the content of that error.
err.code actually has the correct value.
About err.error_string I don't know. I'm new to GO and i have some questions:
Since the C struct has the field char* error_string, is error_string *byte in my GO struct correct?
Should I use []byte or something else?
How do I read the content of the error_string field?
fmt.Println(err.error_string) prints the memory address
fmt.Println(*err.error_string) prints always "101"
1) I doubt that cost char* meant to be UTF16 encoded. So all what you need is just getting raw data:
sensigrafo := "en\000" // \000 = 0 = null termination, \0 does not valid
options := "\000"
...
uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&sensigrafo))
uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&options))
// *(*unsafe.Pointer) are accessing the first field of string header:
type string struct {
data *byte
len int
}
// same with slices
// but for them there's less ugly way:
sensigrafo := []byte("en\000")
options := []byte("\000")
uintptr(unsafe.Pointer(&sensigrafo[0]))
uintptr(unsafe.Pointer(&options[0]))
2) C's int and Golang's int might have different sizeof, so this requires cgo declaration (C.int) or manual matching with random selection (try also int32, int64 if you don't want to use cgo)
type senseiErr struct {
code C.int /* Golang's int32/int64 */
error_string *byte // pointer types are same as C's void* or Golang's unsafe.Pointer
}
Wrong offset might cause error_string be empty or point to random addr.
3) To read content you have to use same methods as C does (read data until null terminated byte, considering that *byte points to first element of string), but I propose to use already implemented runtime functions:
//go:linkname gostringn runtime.gostringn
func gostringn(p *byte, l int) string
//go:linkname findnull runtime.findnull
//go:nosplit
func findnull(s *byte) int
...
error_string := gostringn(err.error_string, findnull(err.error_string))
// or cgo one:
type senseiErr struct {
code C.int
error_string *C.char
}
...
error_string := C.GoString(err.error_string)
There is struct of MyStruct.
type MyStruct struct {
Code int `json:"Code"`
Flags uint8 `json:"Flags"`
OptionField int `json:",omitempty"`
}
Following code convert it to json.
f := MyStruct{Code:500, OptionField:41}
r, _ := json.Marshal(f)
fmt.Println(string(r)
I need to "OptionField" be optional. Some time it should exist in json with one of values [0, 1, 2, 3, ]. and in the other time it should exclude from json.
My problem is: omitempty will exclude it when the value is zero, and the default value of int is zero. Is there any way to omit field in condition (ex: omit if value is -1). Or there is any way to do it.
You could use *int instead of int and set the pointer value to nil in order to omit this.
package main
import (
"encoding/json"
"fmt"
)
type MyStruct struct {
Code int `json:"Code"`
Flags uint8 `json:"Flags"`
OptionField *int `json:",omitempty"`
}
func format(s MyStruct) string {
r, _ := json.Marshal(s)
return string(r)
}
func main() {
f := MyStruct{Code: 500, Flags: 10, OptionField: new(int)}
fmt.Println(format(f)) // {"Code":500,"Flags":10,"OptionField":0}
f.OptionField = nil
fmt.Println(format(f)) // {"Code":500,"Flags":10}
}
I have some different structs like Big with Small embedded at offset 0.
How can I access Small's structure fields from code, that doesn't know anything about Big type, but it is known that Small is at offset 0?
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
var v interface{} = Big{}
// here i only know about 'Small' struct and i know that it is at the begining of variable
v.(Small).val // compile error
It seems that compiler is theoretically able to operate such expression, because it knows that Big type has Small type embedded at offset 0. Is there any way to do such things (maybe with unsafe.Pointer)?
While answer with reflection is working but it has performance penalties and is not idiomatic to Go.
I believe you should use interface. Like this
https://play.golang.org/p/OG1MPHjDlQ
package main
import (
"fmt"
)
type MySmall interface {
SmallVal() int
}
type Small struct {
val int
}
func (v Small) SmallVal() int {
return v.val
}
type Big struct {
Small
bigval int
}
func main() {
var v interface{} = Big{Small{val: 3}, 4}
fmt.Printf("Small val: %v", v.(MySmall).SmallVal())
}
Output:
Small val: 3
Avoid using unsafe whenever possible. The above task can be done using reflection (reflect package):
var v interface{} = Big{Small{1}, 2}
rf := reflect.ValueOf(v)
s := rf.FieldByName("Small").Interface()
fmt.Printf("%#v\n", s)
fmt.Printf("%#v\n", s.(Small).val)
Output (try it on the Go Playground):
main.Small{val:1}
1
Notes:
This works for any field, not just the first one (at "offset 0"). This also works for named fields too, not just for embedded fields. This doesn't work for unexported fields though.
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
func main() {
var v = Big{Small{10},200}
print(v.val)
}
I am writing a generic function to get the size of any type of structure, similar to sizeof function in C.
I am trying to do this using interfaces and reflection but I'm not able to get the correct result. Code is below:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
type myType struct {
a int
b int64
c float32
d float64
e float64
}
info := myType{1, 2, 3.0, 4.0, 5.0}
getSize(info)
}
func getSize(T interface{}) {
v := reflect.ValueOf(T)
const size = unsafe.Sizeof(v)
fmt.Println(size)
}
This code returns wrong result as 12. I am very new to Go, kindly help me on this.
You're getting the size of the reflect.Value struct, not of the object contained in the interface T. Fortunately, reflect.Type has a Size() method:
size := reflect.TypeOf(T).Size()
This gives me 40, which makes sense because of padding.
Go 1.18
With Go 1.18 you can use a generic function with unsafe.Sizeof:
func getSize[T any]() uintptr {
var v T
return unsafe.Sizeof(v)
}
Note that this will be more performant than using reflect, but it will introduce unsafe in your code base — some static analysis tools may give warnings about that.
However if your goal is to improve code reuse or get sizes at run time (read on for the solution to that), this won't help much because you still need to call the function with proper instantiation:
type myType struct {
a int
b int64
c float32
d float64
e float64
}
func main() {
fmt.Println(getSize[myType]())
}
You might get the most out of this when used as part of some other generic code, e.g. a generic type or function where you pass a type param into getSize. Although if you have the argument v this is equivalent to calling unsafe.Sizeof(v) directly. Using a function could be still useful to hide usage of unsafe. A trivial example:
func printSize[T any](v T) {
// (doing something with v)
// instantiate with T and call
s := getSize[T]()
// s := unsafe.Sizeof(v)
fmt.Println(s)
}
Otherwise you can pass an actual argument to getSize. Then type inference will make it unnecessary to specify the type param. This code perhaps is more flexible and allows you to pass arbitrary arguments at runtime, while keeping the benefits of avoiding reflection:
func getSize[T any](v T) uintptr {
return unsafe.Sizeof(v)
}
func main() {
type myType struct {
a int
b int64
c float32
d float64
e float64
}
info := myType{1, 2, 3.0, 4.0, 5.0}
// inferred type params
fmt.Println(getSize(info)) // 40
fmt.Println(getSize(5.0)) // 8
fmt.Println(getSize([]string{})) // 24
fmt.Println(getSize(struct {
id uint64
s *string
}{})) // 16
}
Playground: https://go.dev/play/p/kfhqYHUwB2S
There are some C objects like unions, structs that contain bitfields and structs whose alignment differs from Go's ABI, that cannot be accessed from Go. Some of these structures cannot be changed to be accessible from Go code as they are part of the API of an existing library.
To marshall such objects into Go structures we thus cannot really use Go code. Instead w have to write the marshalling code in C. This works fine but I have not found a feasible way to define C functions that operate on types defined in Go code. Right now I am defining the data types I am marshalling into on the C side and use these data types in my Go code.
This is really nasty if I want to expose the marshalled types as an API in my Go code, as I cannot expose a C type as a part of my package interface. My current approach involves remarshalling the already marshalled object into a type that is defined in Go code.
Is there a more elegant way to do what I want to do, i.e. marshalling C structs that cannot be accessed from Go code into data types defined in Go code?
As requested in the comment section, here is a collection of C objects that cannot be accessed from Go.
#include <complex.h>
#include <stdbool.h>
union foo {
int i;
float f;
};
struct bar {
bool x:1;
unsigned int y:3;
unsigned int z:4;
};
struct baz {
float f;
complex float c;
};
#pragma pack 1
struct quux {
char c;
short s;
int i;
};
The standard package encoding/binary can be used for manipulating raw C structs.
You can extend Read and Write functions to support custom types :
func Read(r io.Reader, order binary.ByteOrder, data interface{}) error {
switch data := data.(type) {
case *foo:
return readFoo(r, order, data)
// (...)
default:
return binary.Read(r, order, data)
}
}
func Write(w io.Writer, order binary.ByteOrder, data interface{}) error {
switch data := data.(type) {
case foo:
return writeFoo(r, order, data)
// (...)
default:
return binary.Write(r, order, data)
}
}
Use a struct containing all the union's fields and use application context to decide which value to encode into the C union.
type foo struct {
is_i bool
i int32
f float32
}
// Read a foo from r into data
func readFoo(r io.Reader, order binary.ByteOrder, data *foo) error {
b := make([]byte, 4)
if _, err := io.ReadFull(r, b); err != nil {
return err
}
*data = foo{
i: int32(order.PutUint32(b)),
f: float32(order.PutUint32(b)),
}
return nil
}
// Write a foo from data into w
func writeFoo(w io.Writer, order binary.ByteOrder, data foo) error {
b := make([]byte, 4)
if data.is_i {
order.PutUint32(b, uint32(data.i))
} else {
order.PutUint32(b, uint32(data.f))
}
_, err := w.Write(b)
return err
}
(Alternatively, using getters and setters: http://pastebin.com/H1QW5AFb)
Use bitwise operations to marshal bitfields
type bar struct {
x bool
y uint
z uint
}
// Read a bar from r into data
func readBar(r io.Reader, order binary.ByteOrder, data *foo) error {
b := make([]byte, 1)
if _, err := io.ReadFull(r, b); err != nil {
return err
}
// Read from bitfield
*data = bar{
x: bool(b[0] >> 7), // bool x:1;
y: uint((b[0] & 0x70) >> 3), // unsigned int y:3;
z: uint(b[0] & 0x0f), // unsigned int z:4;
}
return nil
}
// Write a bar from data into w
func writeBar(w io.Writer, order binary.ByteOrder, data bar) error {
b := make([]byte, 1)
var x uint8
if data.x {
x = 1
}
// Create bitfield
b[0] = (x & 0x01 << 7) & // bool x:1;
(uint8(data.y) & 0x03 << 4) & // unsigned int y:3;
(uint8(data.z) & 0x04) // unsigned int z:4;
_, err := w.Write(b)
return err
}
The serialized form of baz depends on the compiler's internal definition of complex.
When using encoding.binary, fields have a 1-byte alignement so quux can be marshaled directly.