The data type conversion involved in CGO includes the following:
- Numeric type
- String and slice types
- Structure, union, enumeration type'
- array type
- pointer type
- Converting between arrays and pointers
- Conversion between slices and slices
We have sorted out the first three in the previous short article, and we will continue
array type
In C language:
- array
In the C language, the array name corresponds to a pointer, pointing to a specific type of memory of a specific length, but this pointer cannot be modified
A string in C language is an array of char type. The length of the string needs to be determined according to the position of the NULL character representing the end.
- string
is an array of type char
- slice
C language has no concept of slice
In the GO language:
- array
An array is a value type, and the length of the array is a part of the array type
- string
It is a read-only byte type memory of a certain length.
- slice
is a simple dynamic array
From the above, we can see that the mutual conversion of arrays, slices, and strings in C language and GO language can be the conversion of pointers and the length of memory pointed to by pointers.
CGO officially provides us with the following 5 functions for the conversion between C language and GO language:
- func C.CString(string) *C.char
C.CString
Clone the incoming go string into a C-formatted string. The cloned string is created by malloc in C language, so we run out of this function and need to release it manually Memory
- func C.CBytes([]byte) unsafe.Pointer
C.CBytes
is used to clone and convert the input go byte type array (slice) into C language pointer. The pointer is an array, which needs to open up space. When not in use, it also needs to be released manually.
- func C.GoString(*C.char) string
C.GoString
Clone C string into GO string, GO itself will release memory
- func C.GoStringN(*C.char, C.int) string
C.GoStringN
, convert a string of a certain length in C into a string of GO, and GO will release memory by itself
- func C.GoBytes(unsafe.Pointer, C.int) []byte
C.GoBytes
Convert C arrays into GO slices
summary:
The above-mentioned set of officially provided functions, the conversion between GO language and C language are realized by cloning
GO to C
C uses malloc to open up memory in C's own space, so when we don't need to use it, we need to release it
C to GO
It is also through cloning, but GO has its own memory management, which does not require us to manually release memory
Advantages of the above functions
- The conversion is performed by cloning, the memory is opened up in the respective language, and the memory management is simple
Disadvantages of the above functions
- Mutual conversion requires additional memory, which increases system overhead
pointer-to-pointer conversion
In cgo, how to realize the conversion between pointers and pointers?
In C language:
Pointers are the soul of the C language. In the C language, coercion can be performed between pointers of different types, 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.
Different types of pointers in GO are forbidden to be converted, but with CGO, this imprisonment is broken, and the unsafe.pointer pointer type can be used as a bridge to convert
E.g
var a *A
var b *B
b = (*b)(unsafe.Pointer(a)) // *A => *B
a = (*a)(unsafe.Pointer(b)) // *B => *A
Conversion between numbers and pointers
In cgo, how to realize the conversion of values and pointers?
In the GO language:
Direct conversion of numeric types to pointer types is prohibited
But with cgo, we have a way. Go unsafe.Pointer
pointer type defines a uintptr type , we still use them as a bridge to convert into our target pointer
For example, how do we convert the value of int32 in a GO to a pointer in C?
As mentioned above, we make good use of this bridge to convert int32 into uintptr, then into unsafe.pointer, and finally into C char pointer
Conversion between slices and slices
In cgo, how to realize the conversion between slices and slices?
The conversion between slices and slices uses the data structure provided by the reflect package in GO.
Because in GO, the array or slice is no longer a pointer type, and it needs to be converted by using the data structure in reflect, as follows:
//它的引用不会被垃圾回收,因此程序必须使用正确类型的指向底层数据的指针
type StringHeader struct {
Data uintptr
Len int
}
//它的引用不会被垃圾回收,因此程序必须使用正确类型的指向底层数据的指针
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
How to convert slice A into slice B?
We can do the conversion like this, first constructing an empty slice
var p []int
var q []string
pk := (*reflect.SliceHeader)(unsafe.Pointer(&p))
qk := (*reflect.SliceHeader)(unsafe.Pointer(&q))
Then use the original data to fill this empty slice, here you need to pay attention 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])
function call
The basic function call we have demonstrated in the last short article, let's look at other
- How the return value of the C function itself is used in GO
How the return value of the C function itself is used in GO
Let's write a C function with a return value, and then call GO again:
The C language does not support multiple return results, but the GO language supports returning one result. In CGO, we can use the <errno.h>
errno
macro in the standard library to return the error status
package main
/*
#include <errno.h>
static int testadd(int a, int b) {
if (a < 0){
errno = EINVAL;
return 0;
}
return a+b;
}
*/
import "C"
import "fmt"
func main() {
v0, err0 := C.testadd(-2, 1)
fmt.Println(v0, err0)
v1, err1 := C.testadd(1, 2)
fmt.Println(v1, err1)
}
The execution result is as follows:
0 invalid argument
3 <nil>
If the C function is no return value, we can also deal with this.
For example it could be
v, _ := C.xxx()
fmt.Printf("%#v", v) // 输出为 main._Ctype_void{}
fmt.Println(C.xxx()) // 输出为 [] 0长的数组类型[0]byte
After we actually practiced it, we found that the void type of the C language corresponds to the _Ctype_void
type in the current main package
A drop of water wears a stone, learn step by step
References:
Welcome to like, follow, favorite
Friends, your support and encouragement are the motivation for me to persist in sharing and improving quality
Okay, here it is this time
Technology is open, and our mentality should be open. Embrace change, live in the sun, and move forward.
I am the native of Abingyun , welcome to like, follow and collect, see you next time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。