cgo: implement C unions

Unions are somewhat hard to implement in Go because they are not a
native type. But it is actually possible with some compiler magic.

This commit inserts a special "C union" field at the start of a struct
to indicate that it is a union. As such a field cannot be written
directly in Go, this is a useful to distinguish structs and unions.
This commit is contained in:
Ayke van Laethem
2019-04-11 23:14:10 +02:00
committed by Ron Evans
parent 536086988c
commit d2b3a5486c
8 changed files with 206 additions and 22 deletions
+18 -1
View File
@@ -8,8 +8,11 @@ double globalDouble = 3.2;
_Complex float globalComplexFloat = 4.1+3.3i;
_Complex double globalComplexDouble = 4.2+3.4i;
_Complex double globalComplexLongDouble = 4.3+3.5i;
collection_t globalStruct = {256, -123456, 3.14};
collection_t globalStruct = {256, -123456, 3.14, 88};
int globalStructSize = sizeof(globalStruct);
short globalArray[3] = {5, 6, 7};
joined_t globalUnion;
int globalUnionSize = sizeof(globalUnion);
int fortytwo() {
return 42;
@@ -26,3 +29,17 @@ int doCallback(int a, int b, binop_t callback) {
void store(int value, int *ptr) {
*ptr = value;
}
void unionSetShort(short s) {
globalUnion.s = s;
}
void unionSetFloat(float f) {
globalUnion.f = f;
}
void unionSetData(short f0, short f1, short f2) {
globalUnion.data[0] = 5;
globalUnion.data[1] = 8;
globalUnion.data[2] = 1;
}
+24 -1
View File
@@ -9,6 +9,10 @@ import "C"
import "unsafe"
func (s C.myint) Int() int {
return int(s)
}
func main() {
println("fortytwo:", C.fortytwo())
println("add:", C.add(C.int(3), 5))
@@ -36,9 +40,28 @@ func main() {
println("complex float:", C.globalComplexFloat)
println("complex double:", C.globalComplexDouble)
println("complex long double:", C.globalComplexLongDouble)
println("struct:", C.globalStruct.s, C.globalStruct.l, C.globalStruct.f)
// complex types
println("struct:", C.int(unsafe.Sizeof(C.globalStruct)) == C.globalStructSize, C.globalStruct.s, C.globalStruct.l, C.globalStruct.f)
var _ [3]C.short = C.globalArray
println("array:", C.globalArray[0], C.globalArray[1], C.globalArray[2])
println("union:", C.int(unsafe.Sizeof(C.globalUnion)) == C.globalUnionSize)
C.unionSetShort(22)
println("union s:", C.globalUnion.s)
C.unionSetFloat(3.14)
println("union f:", C.globalUnion.f)
C.unionSetData(5, 8, 1)
println("union global data:", C.globalUnion.data[0], C.globalUnion.data[1], C.globalUnion.data[2])
println("union field:", printUnion(C.globalUnion).f)
}
func printUnion(union C.joined_t) C.joined_t {
println("union local data: ", union.data[0], union.data[1], union.data[2])
union.s = -33
println("union s method:", union.s.Int(), union.data[0] == 5)
union.f = 6.28
println("union f:", union.f)
return union
}
//export mul
+16 -3
View File
@@ -6,11 +6,21 @@ typedef int * intPointer;
void store(int value, int *ptr);
typedef struct collection {
short s;
long l;
float f;
short s;
long l;
float f;
unsigned char c;
} collection_t;
typedef union joined {
myint s;
float f;
short data[3];
} joined_t;
void unionSetShort(short s);
void unionSetFloat(float f);
void unionSetData(short f0, short f1, short f2);
// test globals
extern int global;
extern _Bool globalBool;
@@ -21,7 +31,10 @@ extern _Complex float globalComplexFloat;
extern _Complex double globalComplexDouble;
extern _Complex double globalComplexLongDouble;
extern collection_t globalStruct;
extern int globalStructSize;
extern short globalArray[3];
extern joined_t globalUnion;
extern int globalUnionSize;
// test duplicate definitions
int add(int a, int b);
+10
View File
@@ -14,3 +14,13 @@ double: +3.200000e+000
complex float: (+4.100000e+000+3.300000e+000i)
complex double: (+4.200000e+000+3.400000e+000i)
complex long double: (+4.300000e+000+3.500000e+000i)
struct: true 256 -123456 +3.140000e+000
array: 5 6 7
union: true
union s: 22
union f: +3.140000e+000
union global data: 5 8 1
union local data: 5 8 1
union s method: -33 false
union f: +6.280000e+000
union field: +6.280000e+000