This is the 29th day of my participation in the August Wenwen Challenge.More challenges in August

CGO learning 1, preliminary cognition and basic data type conversion

What is CGO?

CGO is a feature of the GO language. CGO is a high-level use of GOLANG, mainly through the use of GOLANG call CLANG implementation of the library

use

We can use

Import “C” to use the CGO feature

One of the simplest CGO to use

package main


//#include <stdio.h>
import "C"

func main(a){
	C.puts(C.CString("Hello, Cgo\n"))}Copy the code

Above the import “C” you can write the library that you want to import. The C library needs to be commented out, and CGO will regard this comment content as C code, which is called preamble.

A functional explanation of the above code

Convert a Go language String to a C language String using the CString function of the CGO package

Finally, call the c.puts function of the CGO package to print the converted C string to the standard output window

Use go build-x main.go to compile

Plus -x prints out the instructions executed during compilation

# go build -x main.go
WORK=/tmp/go-build594331603
mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile command-line-arguments=/root/.cache/go-build/fb/fbb37eeb6735cb453f6d92e2e3f46f14d9dceb5baa1cdd10aae11d1d47d60e55-d
packagefile runtime/cgo=/usr/local/go/pkg/linux_amd64/runtime/cgo.a
packagefile syscall=/usr/local/go/pkg/linux_amd64/syscall.a
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
packagefile errors=/usr/local/go/pkg/linux_amd64/errors.a
packagefile internal/bytealg=/usr/local/go/pkg/linux_amd64/internal/bytealg.a
packagefile internal/oserror=/usr/local/go/pkg/linux_amd64/internal/oserror.a
packagefile internal/race=/usr/local/go/pkg/linux_amd64/internal/race.a
packagefile internal/unsafeheader=/usr/local/go/pkg/linux_amd64/internal/unsafeheader.a
packagefile sync=/usr/local/go/pkg/linux_amd64/sync.a
packagefile internal/cpu=/usr/local/go/pkg/linux_amd64/internal/cpu.a
packagefile runtime/internal/atomic=/usr/local/go/pkg/linux_amd64/runtime/internal/atomic.a
packagefile runtime/internal/math=/usr/local/go/pkg/linux_amd64/runtime/internal/math.a
packagefile runtime/internal/sys=/usr/local/go/pkg/linux_amd64/runtime/internal/sys.a
packagefile internal/reflectlite=/usr/local/go/pkg/linux_amd64/internal/reflectlite.a
packagefile sync/atomic=/usr/local/go/pkg/linux_amd64/sync/atomic.a
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/linux_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=Vv0to6CWqbWf5_KTN66F/K36AEO-x4qJ_LJbz5wgG/HVbBbLSaW0sTSwlN8TzN/Vv0to6CWqbWf5_KTN66F -extld=gcc /root/.cache/go-build/fb/fbb37eeb6735cb453f6d92e2e3f46f14d9dceb5baa1cdd10aae11d1d47d60e55-d
/usr/local/go/pkg/tool/linux_amd64/buildid -w $WORK/b001/exe/a.out # internal
mv $WORK/b001/exe/a.out main
rm -r $WORK/b001/

Copy the code

Try writing a C function yourself and letting GO call it

The SayHello function is called in the Go context

package main

/*
#include <stdio.h>

static void SayHello(const char* s) {
    puts(s);
}
*/
import "C"

func main(){
	C.SayHello(C.CString("hello xiaomotong study cgo\n"))
}

Copy the code

Try writing a C file yourself and importing and calling it in GO

xmtC.h

void SayHi(const char * str);
Copy the code

xmtC.c

C files must be in the same directory, cgo use go build, will default to the same directory to find. C files for compilation, if we need to make c files into static libraries or dynamic libraries, then do not put c source files in the same directory, avoid the same name.

#include <stdio.h>
#include "xmtC.h"

void SayHi(const char * str){
    puts(str);
}
Copy the code

main.go

package main

//void SayHi(const char * str);
import "C"

func main(a){
	C.SayHi(C.CString("hello xiaomotong study cgo\n"))}Copy the code

Run go Build directly to compile and run the executable

# go build
# ls
cgo  main.go  xmtC.c
# ./cgo
hello xiaomotong study cgo
Copy the code

Through C interface oriented programming technology, we not only free the implementers of functions, but also simplify the users of functions. Now we can use SayHi as a library function (similar to the puts function)

We could also write it like this in the GO file

package main

//#include <xmtC.h>
import "C"

func main(a){
	C.SayHi(C.CString("hello xiaomotong study cgo\n"))}Copy the code

Merge C and GO code

In Go1.10, CGO added a _GoString_ predefined C type to represent the Go language string

/ / + build go1.10

package main

//void SayHi(_GoString_ s);
import "C"

import (
	"fmt"
)

func main(a) {
	C.SayHi("hello xiaomotong study cgo\n")}//export SayHi
func SayHi(s string) {
	fmt.Print(s)
}
Copy the code

The logical order of execution is as follows:

CGO environment

Using CGO requires certain environmental support

  • This is required for Linuxgcc/g++Compiler environment
  • Windows requires MinGW tools
  • You need to put the environment variable of GOCGO_ENABLEDSetting 1

There are a few things to note in the above example:

  • Import “C” statements cannot be placed with other import statements and must be placed on a separate line

  • CString(” Hello xiaomotong study cgo\n”) is a virtual package that calls C to convert a String into a CString

  • Go is a strongly typed language

    Therefore, the type of the parameter passed in CGO must be exactly the same as the declared type, and must be converted into the corresponding C type by the conversion function in “C” before transmission. Variables of the type in Go cannot be directly passed in

    C symbols imported through virtual C packages do not need to start with a capital letter and are not subject to Go’s export rules

# cgo usage

We can use the #cgo statement to set parameters for the compile and link phases

  • Parameters for compile time

It is used to define related macros and specify header file retrieval paths

  • Parameters for the link stage

Basically, you specify the library file retrieval path and the library file to link to

For example, we could do this

// #cgo CFLAGS: -DPNG_DEBUG=1 -I./include
// #cgo LDFLAGS: -L/usr/local/lib -lpng
// #include <png.h>
import "C"
Copy the code

CFLAGS

  • -DPNG_DEBUG

Define the macro PNG_DEBUG, set to 1

  • -I

The retrieval directory for defining header files is./include

LDFLAGS

  • -L

Specify the directory to retrieve library files when linking. You can write ${SRCDIR} to indicate the absolute path of the current package

  • -l

The library needed to specify the link, in this case the PNG library

Conditional build tag

When we go build, we add some conditional parameters. Of course, this conditional parameter is required in the corresponding file.

For example, when we used Go1.10 above, we added // +build Go1.10 to the file

We can use it like this:

go build -tags="debug"
go build -tags="debug test"
go build -tags="linux,386"
Copy the code

If there are more than one tags, we can write them together, using Spaces to indicate or, and using commas to indicate and

GO and C data types are converted to each other

Cgo officially provides the following data type conversions:

C language type CGO type Go language types
char C.char byte
singed char C.schar int8
unsigned char C.uchar uint8
short C.short int16
unsigned short C.ushort uint16
int C.int int32
unsigned int C.uint uint32
long C.long int32
unsigned long C.ulong uint32
long long int C.longlong int64
unsigned long long int C.ulonglong uint64
float C.float float32
double C.double float64
size_t C.size_t uint

Three points to note:

  • In CGO, C int and long correspond to a 4-byte memory size, and size_t can be treated as a Uint unsigned integer in Go

  • In CGO, THE int of C language is fixed at 4 bytes, while the int and uint of GO language correspond to 4 bytes and 8 bytes respectively in 32-bit and 64-bit systems

  • For example, if a datatype has Spaces in the middle and an unsigned int cannot be accessed directly through c. unsigned int, you can use the typedef keyword to provide a regular type name that is easier to access in CGO

String and slice type

The _cGO_export. h header file generated by CGO contains representations of data types such as strings, slices, channels, dictionaries and interfaces in GO, but we generally use strings and slices as valuable representations

Because CGO does not provide helper functions for other data types

typedef struct { const char *p; GoInt n; } GoString;
Copy the code

When we export the function, we can write:

Use the _GoString_ predefined type, which can be written to reduce the risk of cyclic dependencies on the _cGO_export.h header file in CGO code

_GoString_ is a character added to Go1.10 specifically for Go

extern void helloString(_GoString_ p0);
Copy the code

We can calculate the length of the string and get the address of the string using the function provided by the official:

size_t _GoStringLen(_GoString_ s);
const char *_GoStringPtr(_GoString_ s);
Copy the code

Struct, union, enum

Struct, Union, and enum of C language are accessed in GO language, and the corresponding relationship can be viewed in the following table

The C language The GO
struct xx C.struct_xx
union xx C.union_xx
enum xx C.enum_xx

** for struct **

The memory layout of the structure follows the common alignment rules of C

C constructs also follow the 32-bit alignment rules in the 32-bit Go environment and the 64-bit alignment rules in the 64-bit Go environment

Structures that specify special alignment rules cannot be accessed in CGO

The structure of C can be accessed in GO in this way

package main

/* struct struct_TEST { int i; float f; }; * /
import "C"
import "fmt"

func main(a) {
	var a C.struct_TEST
	a.i = 1
	a.f = 2

	fmt.Println(a.i)
	fmt.Println(a.f)
}

Copy the code

Note the following two points:

  • The names of structure members are treated the same as the names of keywords in GO

For example, the structure member name looks like this

struct struct_TEST {
    int type;
    float f;
};
Copy the code

When we access type, we can access a._type like this

What if the structure looks like this?

struct struct_TEST {
    int type;
    float _type;
};
Copy the code

We are still accessing this, a._type, but we are actually accessing float _type; , there is no way to access int type through GO;

Zero-length arrays and bit fields in C are also not accessible in GO, for example

struct struct_TEST { int size: 10; // Bit fields cannot access float arr[]; // a zero-length array cannot be accessed};Copy the code
  • In C, there is no direct access to the struct types defined by Go

For enumeration enum

The enumeration type corresponds to the underlying int, and supports negative values, which can be accessed directly using C.x

For example, the enumeration type is:

enum TEST {
    ONE,
    TWO,
};
Copy the code

With this type we can use c.ennum_test

To copy this variable, we can do this: c = c.ne

For union union

C union types are not supported in Go; they are converted to arrays of bytes of corresponding size

For example,

union B1 {
    int i;
    float f;
};
Copy the code

Union B1 is converted into a 4 byte size byte array [4]uint8

There are three ways to manipulate union variables in GO:

  • Define helper functions in C
  • The Goencoding/binaryManually decode members **(be aware of big end and small end issues)**
  • useunsafePackage forces a cast to the corresponding type

For example

package main

/*
#include <stdint.h>

union TEST {
    int i;
    float f;
};
*/
import "C"
import (
	"fmt"
	"unsafe"
)

func main() {
	var b C.union_TEST

	*(*C.int)(unsafe.Pointer(&b)) = 1

	fmt.Println("b.i:", *(*C.int)(unsafe.Pointer(&b)))
	fmt.Println("b.f:", *(*C.float)(unsafe.Pointer(&b)))
}
Copy the code

The unsafe package performs best when reading and writing union variables, where Pointers are retrieved and then converted to the corresponding data type

References:

GO Advanced Programming

Welcome to like, follow and favorites

Friends, your support and encouragement, I insist on sharing, improve the quality of the power

All right, that’s it for this time

Technology is open, our mentality, should be more open. Embrace change, live in the sun, and strive to move forward.

I am Nezha, welcome to like, see you next time ~