202 lines
2.7 KiB
Markdown
202 lines
2.7 KiB
Markdown
|
# CGO 的基本使用
|
|||
|
|
|||
|
## Go 调用 C
|
|||
|
|
|||
|
### 内联编码
|
|||
|
|
|||
|
```go
|
|||
|
package main
|
|||
|
|
|||
|
/*
|
|||
|
#include <stdio.h>
|
|||
|
int test() {
|
|||
|
return 2016;
|
|||
|
}
|
|||
|
*/
|
|||
|
import "C"
|
|||
|
|
|||
|
import "fmt"
|
|||
|
|
|||
|
func main() {
|
|||
|
fmt.Println(C.test())
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
编译命令如下:
|
|||
|
|
|||
|
```bash
|
|||
|
CGO_ENABLED=1 CC=gcc go build
|
|||
|
```
|
|||
|
|
|||
|
### 静态链接
|
|||
|
|
|||
|
C 代码写在 .c 和 .h 独立文件中,与 Go 代码共同编译。
|
|||
|
|
|||
|
```cpp
|
|||
|
/**
|
|||
|
* @file: demo.h
|
|||
|
*/
|
|||
|
#ifndef DEMO_H
|
|||
|
#define DEMO_H
|
|||
|
|
|||
|
#include <stdint.h>
|
|||
|
|
|||
|
__attribute__ ((visibility("default"))) extern int32_t test003_init(int32_t i);
|
|||
|
|
|||
|
#endif // DEMO_H
|
|||
|
```
|
|||
|
|
|||
|
```cpp
|
|||
|
/**
|
|||
|
* @file: demo.c
|
|||
|
*/
|
|||
|
#include "demo.h"
|
|||
|
|
|||
|
int32_t test003_init(int32_t i) {
|
|||
|
return i*i;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
main.go 如下:
|
|||
|
|
|||
|
```go
|
|||
|
package main
|
|||
|
|
|||
|
/*
|
|||
|
#cgo CFLAGS : -I./
|
|||
|
|
|||
|
#include "demo.h"
|
|||
|
*/
|
|||
|
import "C"
|
|||
|
|
|||
|
import "fmt"
|
|||
|
|
|||
|
func main() {
|
|||
|
i := C.test003_init(C.int(3))
|
|||
|
fmt.Println(i)
|
|||
|
fmt.Println("Hi")
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
编译命令如下:
|
|||
|
|
|||
|
```bash
|
|||
|
CGO_ENABLED=1 CC=gcc go build
|
|||
|
```
|
|||
|
|
|||
|
### 动态链接
|
|||
|
|
|||
|
C 代码写在 .c 和 .h 独立文件中,与 Go 代码分开编译。
|
|||
|
|
|||
|
```cpp
|
|||
|
/**
|
|||
|
* @file: demo.h
|
|||
|
*/
|
|||
|
#ifndef DEMO_H
|
|||
|
#define DEMO_H
|
|||
|
|
|||
|
#include <stdint.h>
|
|||
|
|
|||
|
__attribute__ ((visibility("default"))) extern int32_t test003_init(int32_t i);
|
|||
|
|
|||
|
#endif // DEMO_H
|
|||
|
```
|
|||
|
|
|||
|
```cpp
|
|||
|
/**
|
|||
|
* @file: demo.c
|
|||
|
*/
|
|||
|
#include "demo.h"
|
|||
|
|
|||
|
int32_t test003_init(int32_t i) {
|
|||
|
return i*i;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
先将 C 代码编译成共享库,编译命令如下:
|
|||
|
|
|||
|
```bash
|
|||
|
gcc -shared -o libdemo.so demo.c
|
|||
|
```
|
|||
|
|
|||
|
main.go 如下:
|
|||
|
|
|||
|
```go
|
|||
|
package main
|
|||
|
|
|||
|
/*
|
|||
|
#cgo CFLAGS : -I./
|
|||
|
#cgo LDFLAGS: -L./ -ldemo
|
|||
|
|
|||
|
#include "demo.h"
|
|||
|
*/
|
|||
|
import "C"
|
|||
|
|
|||
|
import "fmt"
|
|||
|
|
|||
|
func main() {
|
|||
|
i := C.test003_init(C.int(3))
|
|||
|
fmt.Println(i)
|
|||
|
fmt.Println("Hi")
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
再编译 Go 代码:
|
|||
|
|
|||
|
```bash
|
|||
|
CGO_ENABLED=1 CC=gcc go build
|
|||
|
```
|
|||
|
|
|||
|
### CGO 中的类型
|
|||
|
|
|||
|
#### 基础类型
|
|||
|
|
|||
|
```go
|
|||
|
C.char
|
|||
|
C.schar(signed char)
|
|||
|
C.uchar(unsigned char)
|
|||
|
C.short
|
|||
|
C.ushort(unsigned short)
|
|||
|
C.int
|
|||
|
C.uint(unsigned int)
|
|||
|
C.long
|
|||
|
C.ulong(unsigned long)
|
|||
|
C.longlong(long long)
|
|||
|
C.ulonglong(unsigned long long)
|
|||
|
C.float
|
|||
|
C.double
|
|||
|
```
|
|||
|
|
|||
|
#### Go string 转 C string
|
|||
|
|
|||
|
```go
|
|||
|
func C.CString(goString string) *C.char
|
|||
|
```
|
|||
|
|
|||
|
转换为 C string 会分配一个内存,因此需要释放,文档中示例如下
|
|||
|
|
|||
|
```go
|
|||
|
// #include <stdlib.h>
|
|||
|
import "C"
|
|||
|
import "unsafe"
|
|||
|
...
|
|||
|
var cmsg *C.char = C.CString("hi")
|
|||
|
defer C.free(unsafe.Pointer(cmsg))
|
|||
|
// do something with the C string
|
|||
|
```
|
|||
|
|
|||
|
#### C string 转 Go string
|
|||
|
|
|||
|
```go
|
|||
|
func C.GoString(cString *C.char) string
|
|||
|
func C.GoStringN(cString *C.char, length C.int) string
|
|||
|
```
|
|||
|
|
|||
|
## C 调用 Go
|
|||
|
|
|||
|
参考 [Build and Use Go Packages as C Libraries](./Build_and_Use_Go_Packages_as_C_Libraries.md)
|
|||
|
|
|||
|
## 注意事项
|
|||
|
|
|||
|
1. Go 调用 C 时,CGO 的注释和 import “C” 之间不能有空行,否则出现“could not determine kind of name for C.xxxxx” 等莫名奇妙的错误。
|