Hi,
the code down use the C operator &xx->out
to access the FIRST entry of an embedded struct and GO use &xx.out
for the same task → the problem is that GO evaluate xx and C not. If you look to the assembler: Compiler Explorer the C compiler translate the &xx->out
into a simple pointer-cast WITHOUT any overhead and GO seems to ignor the fact.
The following C code works fine:
#include <stdlib.h>
#include <stdio.h>
struct base {
int b;
};
struct A {
struct base obj;
int a;
};
void method_base (struct base* hdl, int val) {
if (hdl == NULL) {
fprintf(stderr,"sorry.\n");
} else {
hdl->b = val;
fprintf(stderr,"set: hdl->b = %d\n", hdl->b);
}
}
int main(int argc, char** argv) {
fprintf(stderr,"init: aO = calloc\n");
struct A * aO = (struct A*) calloc(1,sizeof(*aO));
fprintf(stderr,"init: bO = NULL\n");
struct A * bO = NULL;
fprintf(stderr,"step: cast aO\n");
method_base((struct base*) aO, 1);
fprintf(stderr,"step: ref aO\n");
method_base(&aO->obj, 2);
fprintf(stderr,"step: cast bO\n");
method_base((struct base*) bO, 3);
fprintf(stderr,"step: ref bO\n");
method_base(&bO->obj, 4);
fprintf(stderr,"step: end.\n");
}
OUTPUT:
init: aO = calloc
init: bO = NULL
step: cast aO
set: hdl->b = 1
step: ref aO
set: hdl->b = 2
step: cast bO
sorry.
step: ref bO
sorry.
step: end.
the following GO code crash
package main
// #include <stdlib.h>
// #include <stdio.h>
// struct base {
// int b;
// };
// struct A {
// struct base obj;
// int a;
// };
// void method_base (struct base* hdl, int val) {
// if (hdl == NULL) {
// fprintf(stderr,"sorry.\n");
// } else {
// hdl->b = val;
// fprintf(stderr,"set: hdl->b = %d\n", hdl->b);
// }
// }
import "C"
import "fmt"
import "unsafe"
import "os"
func main() {
fmt.Fprintf(os.Stderr,"init: aO = calloc\n");
aO := (*C.struct_A)(C.calloc(1,C.sizeof_struct_A));
fmt.Fprintf(os.Stderr,"init: bO = NULL\n");
bO := (*C.struct_A)(C.NULL);
fmt.Fprintf(os.Stderr,"step: cast aO\n");
C.method_base((*C.struct_base)(unsafe.Pointer(aO)), 1);
fmt.Fprintf(os.Stderr,"step: ref aO\n");
C.method_base(&aO.obj, 2);
fmt.Fprintf(os.Stderr,"step: cast bO\n");
C.method_base((*C.struct_base)(unsafe.Pointer(bO)), 3);
fmt.Fprintf(os.Stderr,"step: ref bO\n");
C.method_base(&bO.obj, 4);
fmt.Fprintf(os.Stderr,"step: end.\n");
}
OUTPUT:
init: aO = calloc
init: bO = NULL
step: cast aO
set: hdl->b = 1
step: ref aO
set: hdl->b = 2
step: cast bO
sorry.
step: ref bO
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x48fbb4]goroutine 1 [running]:
main.main()
…/main.go:39 +0x224