Golang go language and C language intermodulation, through CGO

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. 1. Good links:


http://tonybai.com/2012/09/26/interoperability-between-go-and-c/
Http://www.mischiefblog.com/2014/06/26/example-cgo-golang-app-that-calls-a-native-library-with-a-c-structure/
http://tonybai.com/2016/02/21/some-changes-in-go-1-6/
Http://blog.giorgis.io/cgo-examples
http://tonybai.com/tag/cgo/
http://cholerae.com/2015/05/17/%E4%BD%BF%E7%94%A8Cgo%E7%9A%84%E4%B8%80%E7%82%B9%E6%80%BB%E7%BB%93/
Http://akrennmair.github.io/golang-cgo-slides/#1


2. CGO rules for C + +


2.1. Mapping the C namespace to Go:


2.1.1 Everything declared in the C code was available in the C pseudo-package
2.1.2 Fundamental C data types have their counterpart, e.g. Int→c.int, unsigned short→c.ushort, etc.
2.1.3 the Go equivalent to void * is unsafe. Pointer
2.1.4 Typedefs is available under their own name
2.1.5 structs is available with a struct_ prefix, e.g. struct Foo→c.struct_foo, same goes for unions and enums

2.2. Conversion between C and Go strings:


2.2.1. The C package contains conversion functions to convert Go to C strings and vice versa
2.2.2. Also:opaque data (behind void *) to []byte
2.2.3. Go string to C string; Result must is freed with C.free:func c.cstring (string) *c.char
2.2.4. C string to Go string:func c.gostring (*c.char) string
2.2.5. C string, length to Go string:func c.gostringn (*c.char, C.int) string
2.2.6. C pointer, length to Go []byte:func c.gobytes (unsafe. Pointer, c.int) []byte

2.3. Go calls C code, go pass to C code of Go pointer refers to the go memory can not contain any point to go memory pointer:


2.3.1. Passing a pointer to a struct

Cgo1_struct.go
Package Main


/*
#include <stdio.h>
struct foo{
int A;
int *p;
};


void PlusOne (struct Foo *f) {
(f->a) + +;
* (f->p) + +;
}
*/
Import "C"
Import "unsafe"
Import "FMT"


Func Main () {
F: = &c.struct_foo{}
F.A = 5
F.P = (*c.int) (unsafe. Pointer) (new (int)))
F.P = &AMP;F.A


C.plusone (f)
Fmt. PRINTLN (int (F.A))
}
As you can see from the Cgo1_struct.go code, go code passes a pointer f to C code that points to go Memory (go Assignment),
But the F-pointing go Memory has a pointer p pointing to another go memory:new (int), let's Run this code:
$go Run Cgo1_struct.go
# command-line-arguments
./cgo1_struct.go:12:2: warning:expression result unused [-wunused-value]
Panic:runtime error:cgo argument have go pointer to Go pointer


Goroutine 1 [Running]:
Panic (0x4068400, 0xc82000a110)
/users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6
Main.main ()
/users/tony/test/go/go16/cgo/cgo1_struct.go:24 +0xb9
Exit Status 2
The code appears panic and prompts: "CGO argument has go pointer to go pointer". Our code violates the CGO pointer delivery rules,
Even if f.p points to a struct's own memory, such as F.P = &AMP;F.A.

2.3.2. Pass a pointer to the struct field:

As stated in the rules, if you pass a pointer to a struct field, then "Go memory" refers to the memory occupied by the field,
Even if there is another field in the struct pointing to the other go memory also matter:

Cgo1_structfield.go
Package Main


/*
#include <stdio.h>
struct foo{
int A;
int *p;
};


void PlusOne (int *i) {
(*i) + +;
}
*/
Import "C"
Import (
"FMT"
"Unsafe"
)


Func Main () {
F: = &c.struct_foo{}
F.A = 5
F.P = (*c.int) (unsafe. Pointer) (new (int)))


C.plusone (&AMP;F.A)
Fmt. PRINTLN (int (F.A))
}
Operation result of the above program:


$go Run Cgo1_structfield.go
6

2.3.3. Pass a pointer to element in the slice or array:

Unlike transitive struct field, when passing a pointer to an element in the slice or array,
The range of Go memory to consider is more than just this element,
This is the area of memory occupied by the underlying array behind the entire array or the entire slice.
Make sure that the area does not contain pointers to any go memory. Let's look at the code example:
Cgo1_sliceelem.go
Package Main


/*
#include <stdio.h>
void PlusOne (int **i) {
(**i) + +;
}
*/
Import "C"
Import (
"FMT"
"Unsafe"
)


Func Main () {
SL: = Make ([]*int, 5)
var a int = 5
SL[1] = &a
C.plusone ((**c.int) (unsafe. Pointer) (&sl[0])))
Fmt. Println (Sl[0])
}
From this code, we see that we are passing the address of the first element of slice, which is &sl[0]. We did not assign a value to Sl[0],
But Sl[1] is assigned to another Go memory address (&a), when we pass &sl[0] to PlusOne, the result is as follows:
$go Run Cgo1_sliceelem.go
Panic:runtime error:cgo argument have go pointer to Go pointer


Goroutine 1 [Running]:
Panic (0X40DBAC0, 0xc8200621d0)
/users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6
Main.main ()
/users/tony/test/go/go16/cgo/cgo1_sliceelem.go:19 +0xe4
Exit Status 2

2.4. c When calling go code:

2.4.1. c called the GO function cannot return a pointer to the memory of Go allocation:

Package Main


extern int* goadd (int, int);
//
static int CAdd (int a, int b) {
int *i = Goadd (A, b);
return *i;
// }
Import "C"
Import "FMT"


Export Goadd
Func Goadd (A, b c.int) *c.int {
c: = a + b
Return &c
}


Func Main () {
var a, b int = 5, 6
I: = C.cadd (C.int (a), C.int (b))
Fmt. PRINTLN (int (i))
}


As you can see: Goadd this go function returns a pointer to the memory (&c) of Go allocation. Run the above code with the following results:
$go Run Cgo2_1.go
Panic:runtime error:cgo result has Go pointer


Goroutine 1 [Running]:
Panic (0X40DBA40, 0xc82006e1c0)
/users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6
MAIN._CGOEXPWRAP_872B2F2E7532_GOADD.FUNC1 (0xc820049d98)
Command-line-arguments/_obj/_cgo_gotypes.go:64 +0x3a
Main._cgoexpwrap_872b2f2e7532_goadd (0x600000005, 0xc82006e19c)
command-line-arguments/_obj/_cgo_gotypes.go:66 +0x89
Main._cfunc_cadd (0x600000005, 0x0)
Command-line-arguments/_obj/_cgo_gotypes.go:45 +0x41
Main.main ()
/users/tony/test/go/go16/cgo/cgo2_1.go:20 +0x35
Exit Status 2

2.4.2. Go code cannot store pointers to go-allocated memory in memory allocated by C:

Cgo2_2.go
Package Main


#include <stdlib.h>
extern void Gofoo (int**);
//
static void Cfoo () {
int **p = malloc (sizeof (int*));
Gofoo (P);
// }
Import "C"


Export Gofoo
Func Gofoo (P **c.int) {
*p = new (C.int)
}


Func Main () {
C.cfoo ()
}
However, for this example, the default godebug=cgocheck=1 bias is not a check problem. Let's change Godebug=cgocheck to =2:
$GODEBUG =cgocheck=2 Go Run cgo2_2.go
Write of Go pointer 0xc82000a0f8 to non-go memory 0x4300000
Fatal error:go pointer stored into NON-GO memory


Runtime stack:
Runtime.throw (0x4089800, 0x24)
/users/tony/.bin/go16/src/runtime/panic.go:530 +0x90
RUNTIME.CGOCHECKWRITEBARRIER.FUNC1 ()
/users/tony/.bin/go16/src/runtime/cgocheck.go:44 +0xae
Runtime.systemstack (0X7FFF5FBFF8C0)
/users/tony/.bin/go16/src/runtime/asm_amd64.s:291 +0x79
Runtime.mstart ()
/users/tony/.bin/go16/src/runtime/proc.go:1048
... ...
Goroutine [Syscall, Locked To thread]:
Runtime.goexit ()
/users/tony/.bin/go16/src/runtime/asm_amd64.s:1998 +0x1
Exit Status 2
Indeed runtime panic:write of Go pointer 0xc82000a0f8 to non-go memory 0x4300000






2.3. Calling Go code from C (1)


Go code can be exported via comment://export <function-name>
It can then is called from C
Package Foo


/*
extern void Myprint (int i);


void Dofoo (void) {
int i;
for (i=0;i<10;i++) {
Myprint (i);
}
}
*/
Import "C"

Export Myprint
Func myprint (i c.int) {
Fmt. Printf ("i =%v\n", UInt32 (i))
}


Func Dofoo () {
C.dofoo ()
}


3. CGO Examples:


Package Pwnam


Basic Rule 1: All C code is put into comments.
/*
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
*/


Basic Rule 2: The "C", "unsafe" package must be imported for Go and C interop.
Import ("C"; "unsafe")


Type Passwd struct {
Uid UInt32; Gid UInt32; Dir string; Shell string
}


Func Getpwnam (name string) *passwd {
CNAME: = c.cstring (name)//basic rule 3:go string to C string.
Defer C.free (unsafe. Pointer (CNAME))//basic rule 4:must Clean mannually and obviously.
CPW: = C.getpwnam (CNAME)//basic rule 5:call C function, types, variables and etc all by C namespace.

Return &passwd{
Uid:uint32 (Cpw.pw_uid), Gid:uint32 (Cpw.pw_uid),
Dir:c.gostring (Cpw.pw_dir), shell:c.gostring (Cpw.pw_shell)}//basic rule 6:c string to go string.
}


4. CGO Compilation and Link example:


#cgo Ldflags:
Package Pcap
/*
#cgo Ldflags:-lpcap
#include <stdlib.h>
#include <pcap.h>
*/
Import "C"
#cgo Pkg-config:
Package STFL
/*
#cgo PKG-CONFIG:STFL
#cgo Ldflags:-LNCURSESW
#include <stdlib.h>
#include <stfl.h>
*/
Import "C"




5. CGO Memory Management principle


Go runtime just go to the memory, regardless of C, and vice versa C just don't care about go

So go's memory has the GC to look after, C's memory to oneself c.free.



Cond...


Note: This article is only my personal notes, if there are errors and omissions, please correct me, study together, my e-mail: htyu_0203_39@sina.com








Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.