package main /* #include #include int fortytwo(void); #include "main.h" #include "test.h" int mul(int, int); #include #cgo CFLAGS: -DSOME_CONSTANT=17 #define someDefine -5 + 2 * 7 bool someBool; */ import "C" // int headerfunc(int a) { return a + 1; } // static int headerfunc_static(int a) { return a - 1; } import "C" import ( "syscall" "unsafe" ) func main() { println("fortytwo:", C.fortytwo()) println("add:", C.add(C.int(3), 5)) var x C.myint = 3 println("myint:", x, C.myint(5)) println("myint size:", int(unsafe.Sizeof(x))) var y C.longlong = -(1 << 40) println("longlong:", y) println("global:", C.global) println("defined ints:", C.CONST_INT, C.CONST_INT2) println("defined floats:", C.CONST_FLOAT, C.CONST_FLOAT2) println("defined string:", C.CONST_STRING) println("defined char:", C.CONST_CHAR) println("defined expr:", C.someDefine) var ptr C.intPointer var n C.int = 15 ptr = C.intPointer(&n) println("15:", *ptr) C.store(25, &n) println("25:", *ptr) cb := C.binop_t(C.add) println("callback 1:", C.doCallback(20, 30, cb)) cb = C.binop_t(C.mul) println("callback 2:", C.doCallback(20, 30, cb)) genericCallbackCall[int]() // variadic functions println("variadic0:", C.variadic0()) println("variadic2:", C.variadic2(3, 5)) // functions in the header C snippet println("headerfunc:", C.headerfunc(5)) println("static headerfunc:", C.headerfunc_static(5)) headerfunc_2() // equivalent types var goInt8 int8 = 5 var _ C.int8_t = goInt8 var _ bool = C.someBool var _ C._Bool = C.someBool // more globals println("bool:", C.globalBool, C.globalBool2 == true) println("float:", C.globalFloat) println("double:", C.globalDouble) println("complex float:", C.globalComplexFloat) println("complex double:", C.globalComplexDouble) println("complex long double:", C.globalComplexLongDouble) println("char match:", C.globalChar == 100) var voidPtr unsafe.Pointer = C.globalVoidPtrNull println("void* match:", voidPtr == nil, C.globalVoidPtrNull == nil, (*C.int)(C.globalVoidPtrSet) == &C.global) println("int64_t match:", C.globalInt64 == C.int64_t(-(2<<40))) // 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.unionfield_s()) C.unionSetFloat(C.float(6.28)) println("union f (C.float):", *C.globalUnion.unionfield_f()) C.unionSetFloat(float32(3.14)) println("union f (float32):", *C.globalUnion.unionfield_f()) C.unionSetData(5, 8, 1) data := C.globalUnion.unionfield_data() println("union global data:", data[0], data[1], data[2]) returnedUnion := printUnion(C.globalUnion) println("union field:", *returnedUnion.unionfield_f()) var _ C.union_joined = C.globalUnion printBitfield(&C.globalBitfield) C.globalBitfield.set_bitfield_a(7) C.globalBitfield.set_bitfield_b(0) C.globalBitfield.set_bitfield_c(0xff) printBitfield(&C.globalBitfield) // elaborated type p := C.struct_point2d{x: 3, y: 5} println("struct:", p.x, p.y) // multiple anonymous structs (inside a typedef) var _ C.point2d_t = C.point2d_t{x: 3, y: 5} var _ C.point3d_t = C.point3d_t{x: 3, y: 5, z: 7} // nested structs/unions var _ C.tagged_union_t var _ C.nested_struct_t var _ C.nested_union_t // recursive types, test using a linked list list := &C.list_t{n: 3, next: &C.struct_list_t{n: 6, next: &C.list_t{n: 7, next: nil}}} for list != nil { println("n in chain:", list.n) list = (*C.list_t)(list.next) } // named enum var _ C.enum_option = C.optionA var _ C.option_t = C.optionA println("option:", C.globalOption) println("option A:", C.optionA) println("option B:", C.optionB) println("option C:", C.optionC) println("option D:", C.optionD) println("option E:", C.optionE) println("option F:", C.optionF) println("option G:", C.optionG) // anonymous enum var _ C.option2_t = C.option2A var _ C.option3_t = C.option3A println("option 2A:", C.option2A) println("option 3A:", C.option3A) // anonymous structs and enums in multiple Go files var _ C.teststruct var _ C.testenum // Check that enums are considered the same width in C and CGo. println("enum width matches:", unsafe.Sizeof(C.option2_t(0)) == uintptr(C.smallEnumWidth)) // Check whether CFLAGS are correctly passed on to compiled C files. println("CFLAGS value:", C.cflagsConstant) // Check array-to-pointer decaying. This signature: // void arraydecay(int buf1[5], int buf2[3][8], int buf3[4][7][2]); // decays to: // void arraydecay(int *buf1, int *buf2[8], int *buf3[7][2]); C.arraydecay((*C.int)(nil), (*[8]C.int)(nil), (*[7][2]C.int)(nil)) // Test CGo builtins like C.CString. cstr := C.CString("string passed to C") println("cstr length:", C.strlen(cstr)) gostr := C.GoString(cstr) println("C.CString:", gostr) charBuf := C.GoBytes(unsafe.Pointer(&C.globalChars[0]), 4) println("C.charBuf:", charBuf[0], charBuf[1], charBuf[2], charBuf[3]) binaryString := C.GoStringN(&C.globalChars[0], 4) println("C.CStringN:", len(binaryString), binaryString[0], binaryString[1], binaryString[2], binaryString[3]) // Test whether those builtins also work with zero length data. println("C.GoString(nil):", C.GoString(nil)) println("len(C.GoStringN(nil, 0)):", len(C.GoStringN(nil, 0))) println("len(C.GoBytes(nil, 0)):", len(C.GoBytes(nil, 0))) println("len(C.GoBytes(C.CBytes(nil),0)):", len(C.GoBytes(C.CBytes(nil), 0))) println(`rountrip CBytes:`, C.GoString((*C.char)(C.CBytes([]byte("hello\000"))))) // Check that errno is returned from the second return value, and that it // matches the errno value that was just set. _, errno := C.set_errno(C.EINVAL) println("EINVAL:", errno == syscall.EINVAL) _, errno = C.set_errno(C.EAGAIN) println("EAGAIN:", errno == syscall.EAGAIN) // libc: test whether C functions work at all. buf1 := []byte("foobar\x00") buf2 := make([]byte, len(buf1)) C.strcpy((*C.char)(unsafe.Pointer(&buf2[0])), (*C.char)(unsafe.Pointer(&buf1[0]))) println("copied string:", string(buf2[:C.strlen((*C.char)(unsafe.Pointer(&buf2[0])))])) // libc: test libm functions (normally bundled in libc) println("CGo sqrt(3):", C.sqrt(3)) println("C sqrt(3):", C.doSqrt(3)) // libc: test basic stdio functionality putsBuf := []byte("line written using C puts\x00") C.puts((*C.char)(unsafe.Pointer(&putsBuf[0]))) // libc: test whether printf works in C. printfBuf := []byte("line written using C printf with value=%d\n\x00") C.printf_single_int((*C.char)(unsafe.Pointer(&printfBuf[0])), -21) } func printUnion(union C.joined_t) C.joined_t { data := union.unionfield_data() println("union local data: ", data[0], data[1], data[2]) *union.unionfield_s() = -33 println("union s:", data[0] == -33) *union.unionfield_f() = 6.28 println("union f:", *union.unionfield_f()) return union } //export mul func mul(a, b C.int) C.int { return a * b } func printBitfield(bitfield *C.bitfield_t) { println("bitfield a:", bitfield.bitfield_a()) println("bitfield b:", bitfield.bitfield_b()) println("bitfield c:", bitfield.bitfield_c()) println("bitfield d:", bitfield.d) println("bitfield e:", bitfield.e) } type Int interface { int | uint } func genericCallbackCall[T Int]() { println("callback inside generic function:", C.doCallback(20, 30, C.binop_t(C.add))) }