I am reading from an io.Reader into a Struct, field by field.
// structFields returns a sequence of reflect.Value
for field := range structFields {
switch field.Kind() {
case reflect.String:
// Omitted
case reflect.Uint8:
value := make([]byte, 2)
reader.Read(value)
var num uint8
err := binary.Read(bytes.NewBuffer(value[:]), binary.LittleEndian, &num)
if err != nil { return err }
field.SetUint(int64(num))
// Case statements for each of the other uint and int types omitted
}
}
Unfortunately the block for reflect.Uint8 needs to be repeated for each of the Uint and Int data types since I need to create the var num correctly in each case.
Is there a way I can simplify this switch statement?
Instead of using var num uint8 and field.SetUint(int64(num)) just pass a pointer to the struct fieldĀ to binary.Read:
ptr := field.Addr().Interface()
err := binary.Read(bytes.NewBuffer(value[:]), binary.LittleEndian, ptr)
And make the case statement say:
case reflect.Uint8, reflect.Int, reflect.Uint, ...:
Then you need to deal with differently-sized numbers. Fortunately you can just pass your reader directly to binary.Read and it'll take care of it:
err := binary.Read(reader, binary.LittleEndian, ptr)
Finally, as FUZxxl says, you can just pass a pointer to the entire struct to binary.Read and it'll do all this for you.
Related
I am trying to create a C struct point and pass it to Go but I keep getting a nil pointer. I have the following in C and calling from Go.
test.h
#include <stdio.h>
typedef struct TestStruct {
int test_int;
} TestStruct;
TestStruct* newTestStruct();
test.c
TestStruct* newTestStruct() {
printf("[C] Creating TestStruct...\n");
TestStruct test = {0};
test.test_int = 10;
TestStruct* testPtr = &test;
if (testPtr == NULL) {
printf("[C] TestStruct is NULL.\n");
}
fflush(stdout);
return testPtr;
}
test.go
package teststruct
import "log"
// #include "test.h"
import "C"
type TestStruct C.struct_TestStruct
func NewTestStruct() *TestStruct {
t := C.newTestStruct()
if t == nil {
log.Errorf("[Go] TestStruct is nil.")
}
return (*TestStruct)(t)
}
It prints off the following:
[C] Creating TestStruct...
[Go] TestStruct is nil.
Why is this nil on the Go side?
You are returning a pointer to a stack-allocated structure in C, which is very wrong.
The pointer returned from newTestStruct is essentially dangling and trying to access any data through it may lead to crashes or worse.
Make sure to allocate data on the heap if you want to return a pointer to it, something like:
TestStruct* newTestStruct() {
printf("[C] Creating TestStruct...\n");
TestStruct* testPtr = (TestStruct*)malloc(sizeof(TestStruct));
testPtr->test_int = 10;
if (testPtr == NULL) {
printf("[C] TestStruct is NULL.\n");
}
fflush(stdout);
return testPtr;
}
By the way, on any half-modern C compiler you'd get a warning for your C code, something like warning: function returns address of local variable [-Wreturn-local-addr]
There is a function that sets a pointer to a nil value:
func nilSetter(x *int) {
x = nil
}
I have such snippet of code:
i := 42
fmt.Println(&i)
nilSetter(&i)
fmt.Println(&i)
Which prints:
0xc42008a000
0xc42008a000
While I expect:
0xc42008a000
nil
I know that it happens because function nilSetter just copy address and sets to nil that copy.
But how can I do it correctly?
The only way to achieve that is with a pointer to a pointer. And it's pretty clunky so it's probably not what you want:
func nilSetter(x **int) {
*x = nil
}
func main() {
x := 2
xp := &x
fmt.Println(xp)
nilSetter(&xp)
fmt.Println(xp)
}
// Output:
// 0x10414020
// <nil>
The reason of such behaviour is because there is no pass by reference in Go.
Two variables can have contents that point to the same storage location. But, it is not possible to have them share the same storage location.
Example:
package main
import "fmt"
func main() {
var a int
var b, c = &a, &a
fmt.Println(b, c) // 0x1040a124 0x1040a124
fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}
From your code, the argument x of nilSetter is pointing to some location but it have its own address and when you are setting a nil to it, you are changing its address not the address of what it is pointing to.
package main
import "fmt"
func nilSetter(x *int) {
x = nil
fmt.Println(x, &x) // <nil> 0x1040c140
}
func main() {
i := 42
fmt.Println(&i) // 0x10414020
nilSetter(&i)
fmt.Println(&i) // 0x10414020
}
That is why pointers always have an exact address even its value is nil
Referencing to a blog post by Dave Cheney: https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Just use return value and assign.
func nilSetter(x *int) *int {
x = nil
return x
}
x = nilSetter(x)
guys! I am a beginner in Go. I have some doubts When I learning reflect package ,here's the code:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func checkError(err error) {
if err != nil {
panic(err)
}
}
type Test struct {
X int
Y string
}
func main() {
fmt.Println("hello world!")
test1()
test2()
}
func test1() {
a := Test{}
fmt.Printf("a: %v %T \n", a, a)
fmt.Println(a)
err := json.Unmarshal([]byte(`{"X":1,"Y":"x"}`), &a)
checkError(err)
fmt.Printf("a: %v %T \n", a, a)
}
func test2() {
fmt.Println("===========================")
m := make(map[string]reflect.Type)
m["test"] = reflect.TypeOf(Test{})
a := reflect.New(m["test"]).Elem().Interface()
fmt.Printf("a: %v %T \n", a, a)
fmt.Println(a)
err := json.Unmarshal([]byte(`{"X":1,"Y":"x"}`), &a)
checkError(err)
fmt.Printf("a: %v %T \n", a, a)
}
and the result :
a: {0 } main.Test
{0 }
a: {1 x} main.Test
===========================
a: {0 } main.Test
{0 }
a: map[X:1 Y:x] map[string]interface {}
Why these two way make different result, Could anyone tell me why, many thanks.
In test2 you're passing in the address of the interface{} containing a Test value. When the value is dereferenced by the json package it only sees an interface{}, and therefor it unmarshals into the default types.
What you need is an interface{} containing a pointer to a Test value.
// reflect.New is creating a *Test{} value.
// You don't want to dereference that with Elem()
a := reflect.New(m["test"]).Interface()
// 'a' contains a *Test value. You already have a pointer, and you
// don't want the address of the interface value.
err := json.Unmarshal([]byte(`{"X":1,"Y":"x"}`), a)
Hi everyone in Golang what will you do if you need to change the pointer (change where the pointer points to rather than change the value where this pointer points to). I know it is really easy in C++ by using reference, like"
void myFunc(Type*& ptr)
{
ptr = anotherPointer;
}
int main
{
Type* ptr = &someValue;
myFunc(ptr); // ptr is moved
}
Or equivalently in C, use pointer's pointer:
void myFunc(Type** ptrsptr)
{
*ptrsptr = anotherPointer;
}
int main
{
Type* ptr = &someValue;
myFunc(&ptr); // ptr is moved
}
I wonder if Golang has this neat feature, or if not, the only way is to set at function's return?
You can use a pointer to a pointer, just like in C
http://play.golang.org/p/vE-3otpKkb
package main
import "fmt"
type Type struct{}
var anotherPointer = &Type{}
func myFunc(ptrsptr **Type) {
*ptrsptr = anotherPointer
}
func main() {
ptr := &Type{}
fmt.Printf("%p\n", ptr)
myFunc(&ptr) // ptr is moved
fmt.Printf("%p\n", ptr)
}
The below example will change the value of variable only:
package main
import "fmt"
func main() {
value := 200
var p1 *int = &value
var p2 **int = &p1
fmt.Printf("Value of variable before updating %v and address of pointer is: %p\n", *p1, p1)
*p1 = 300
fmt.Printf("Value of variable after updating by p1 %v and address of pointer is: %p\n", *p1, p1)
**p2 = 400
fmt.Printf("Value of variable after updating by p2 %v and address of pointer is: %p\n", *p1, p1)
}
The below code will change the pointer value and also point to new address:
package main
import "fmt"
func changePointer(newP **int) {
val := 500
*newP = &val
}
func main() {
value := 200
var p1 *int = &value
fmt.Printf("Value of variable before updating %v and address of pointer is: %p\n", *p1, p1)
changePointer(&p1)
fmt.Printf("Value of variable after updating %v and address of pointer is: %p\n", *p1, p1)
}
I'm trying to use a file pointer that I have declared in a structure of linked list, but I keep getting it as a NULL value.
I have the following structure:
struct _hash_table
{
char found;
struct _hash_chain *hash_chain;
}
struct _hash_chain
{
uint64_t value;
FILE *fout;
struct _hash_chain *next;
}
and
struct _hash_table hash_table[TABLE_SIZE];
I keep getting hash_table[i]->hash_chain->fout = NULL and it's pointer address is nil.
Do I need to dynamically allocate memory for the pointer?
struct _hash_table hash_table[TABLE_SIZE]; - This will not allocate memory for struct _hash_chain because hash_chain is pointer variable in _hash_table.
...
struct _hash_table hash_table[TABLE_SIZE];
for (i = 0; i < TABLE_SIZE; i++);
{
hash_table[i].hash_chain = (struct _hash_chain *)malloc(sizeof(struct _hash_chain));
memset(hash_table[i].hash_chain, 0, sizeof(struct _hash_chain));
}
//Then do file open for TABLE_SIZE times
//hash_table[0].hash_chain->fout = fopen("file.txt", "w");
...
Accssing h_table[i].hash_chain without dynamic memory allocation will leads to crash(an undefined behaviour). I hope you will take care of next pointer.