This is the 30th day of my participation in the August Text Challenge.More challenges in August

CGO learning 2, basic data type conversions 2 and function calls

The data type conversion involved in CGO includes the following:

  • Numeric types
  • String and slice type
  • Struct, union, enumeration type ‘
  • An array type
  • Pointer types
  • Conversions between arrays and Pointers
  • Transitions between slices and slices

The first three have been sorted out in the last essay, so continue

An array type

C language:

  • An array of

In C, the array name corresponds to a pointer to a specific type of memory of a specific length, but this pointer cannot be modified

A C string is an array of type char. The length of the string depends on the position of the terminating NULL character

  • string

Is an array of type char

  • slice

C has no concept of slicing

In the GO language:

  • An array of

An array is a value type, and the length of an array is part of the array type

  • string

A block of read-only byte memory of definite length

  • slice

Is a simple dynamic array

As can be seen from the above, the conversion of arrays, slices and strings between C and GO languages can be the conversion of Pointers and the length of memory pointed to by Pointers

CGO officially provides us with the following five functions for the mutual conversion between C language and GO language:

  • func C.CString(string) *C.char

CString Clone the go String into a C format String. The cloned String is created using malloc in C language. Therefore, we have used up this function and need to manually free the memory

  • func C.CBytes([]byte) unsafe.Pointer

C.CBytes is used to clone and convert the input array (slice) of the go byte type into Pointers in C language. Pointers are arrays that need to be allocated space and manually released when not in use

  • func C.GoString(*C.char) string

C.GoString clone C string into GO string, GO itself will free memory

  • func C.GoStringN(*C.char, C.int) string

C. Stringn, converts a string of C length to a string of GO, which will free memory itself

  • func C.GoBytes(unsafe.Pointer, C.int) []byte

C. gobytes convert arrays of C into slices of GO

Summary:

A set of functions provided by the government above, GO language and C language conversion are achieved by cloning

GO to C

C uses malloc to open up memory in C’s own space, so we need to free it up when we don’t need it

C. turn to GO

Again by cloning, but GO has its own memory management and does not require us to manually free memory

Advantages of the above functions

  • In the way of cloning conversion, memory is opened up in their own language, memory management is simple

Disadvantages of the above functions

  • Converting to each other requires extra memory, increasing the system overhead

Conversion between Pointers and Pointers

How to convert Pointers to Pointers in CGO?

C language:

Pointers are the soul of C language. In C language, different types of Pointers can be cast, and free conversion between Pointers is also the first important problem to be solved in CGO code

In the GO language:

The different types of conversions are very strict, and any warning message that might appear in C might be an error in Go.

Pointers to different types in GO are forbidden to be converted, but CGO breaks that barrier by using the unsafe.pointer type as a bridge

For example,

var a *A
var b *B

b = (*b)(unsafe.Pointer(a)) // *A => *B
a = (*a)(unsafe.Pointer(b)) // *B => *A
Copy the code

Conversion between values and Pointers

How to convert values and Pointers in CGO?

In the GO language:

It is forbidden to convert numeric types directly to pointer types

But with cgo, we have a special uintptr for the unsafe.Pointer type in Go, which we still use as a bridge to convert to our purpose Pointer

For example, how do we convert a value int32 in GO to a pointer in C?

As mentioned above, we’ll use this bridge to transform int32 to uintptr, then to uint. pointer, and finally to char for C

Transitions between slices and slices

How to convert slices from slice to slice in CGO?

To convert slices from slice to slice, use the data structure provided by the Reflect package in GO,

Because the array or slice in GO is no longer a pointer, we need to use the data structure in Reflect to convert it, as follows:

// Its reference is not garbage collected, so the program must use the correct type of pointer to the underlying data
type StringHeader struct {
    Data uintptr
    Len  int
}

// Its reference is not garbage collected, so the program must use the correct type of pointer to the underlying data
type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}
Copy the code

How to convert slice A into slice B?

We can do this by constructing an empty slice

var p []int
var q []string

pk := (*reflect.SliceHeader)(unsafe.Pointer(&p))
qk := (*reflect.SliceHeader)(unsafe.Pointer(&q))
Copy the code

The empty slice is then filled with the original data, and attention should be paid to the calculation and assignment of len and CAP

pk.Data = qk.Data
pk.Len = qk.Len * unsafe.Sizeof(q[0]) / unsafe.Sizeof(p[0])
pk.Cap = qk.Cap * unsafe.Sizeof(q[0]) / unsafe.Sizeof(p[0])
Copy the code

A function call

The basic function calls we demonstrated in the last article, let’s look at the others

  • How does the return value of the C function itself apply in GO

How does the return value of the C function itself apply in GO

Let’s write a C function that returns a value, and then GO calls it:

C language does not support multiple return results, but GO language support return a result, CGO inside we can use

standard library errno macro used to return error status

package main

/* #include 
      
        static int testadd(int a, int b) { if (a < 0){ errno = EINVAL; return 0; } return a+b; } * /
      
import "C"
import "fmt"

func main(a) {
	v0, err0 := C.testadd(2 -.1)
	fmt.Println(v0, err0)

	v1, err1 := C.testadd(1.2)
	fmt.Println(v1, err1)
}
Copy the code

The result is as follows:

0 invalid argument
3 <nil>
Copy the code

If C’s function returns no value, we can do the same.

For example, it could look like this

V, _ : = C.x xx (FMT). The Printf (" % # v ", v) / / output as the main _Ctype_void {} FMT. Println (C.x xx ()) / / output [0] to [] 0 long array type byteCopy the code

We found that the V OID type of C language corresponds to the _Ctype_void type in the current main package

Constant dropping wears away a stone

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 ~