這裡寫自定義目錄标題
- 1. 對照表
- 2. 隐藏的坑
-
- 2.1 嵌入式
- 2.2 獨立式
1. 對照表
首先,來看 golang 和 C 的類型轉換對照表:
C語言類型 | CGO類型 | Go語言類型 |
---|---|---|
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 |
值得注意的是,C 中的整形比如 int 在标準中是沒有定義具體字長的,但一般預設認為是 4 位元組,對應 CGO 類型中 C.int 則明确定義了字長是 4 ,但 golang 中的 int 字長則是 8 ,是以對應的 golang 類型不是 int 而是 int32 。為了避免誤用,C 代碼最好使用 C99 标準的數值類型,對應的轉換關系如下:
C語言類型 | CGO類型 | Go語言類型 |
---|---|---|
int8_t | C.int8_t | int8 |
uint8_t | C.uint8_t | uint8 |
int16_t | C.int16_t | int16 |
uint16_t | C.uint16_t | uint16 |
int32_t | C.int32_t | int32 |
uint32_t | C.uint32_t | uint32 |
int64_t | C.int64_t | int64 |
uint64_t | C.uint64_t | uint64 |
2. 隐藏的坑
在Go中調用C一共有兩種辦法:
- 第一種是将C代碼直接嵌入到GO源檔案中
- 第二種是将C代碼寫在C檔案中,再在GO檔案中引入
2.1 嵌入式
第一種實作起來比較順滑,如絲一般,但是沒有進行分檔案夾管理,看上去很不爽,同時也隐藏了一個坑,直接看一個栗子:
package main
/*
#include <stdio.h>
static int32_t add(int32_t a, int32_t b){
return a+b;
}
*/
import "C"
import "fmt"
func main() {
var a, b int32 = 1, 2
c := int32(C.add(C.int32_t(a), C.int32_t(b)))
fmt.Println(c)
}
如果在c代碼與“import “C””之間留一個空行,直接報錯如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5EjN1UjNxETM3ATNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
去掉空行後就ok啦~,結果如下:
2.2 獨立式
第二種實作實作起來坑就大大的了,no bb, 直接上栗子:
//foo.c
#include <stdio.h>
//int count = 6;
void foo() {
printf("I am foo!\n");
}
//foo.h
int count = 6;
void foo();
package main
// #include <stdio.h>
// #include <stdlib.h>
// #include "foo.h"
import "C"
import "fmt"
func main() {
fmt.Println(C.count)
C.foo()
}
佛曰:衆生都是這麼幹的,一般分為兩步:
- 将C檔案編譯成動态連結庫libfoo.so
- 使用指令go build foo.go編譯生成可執行檔案
但在第二步的編譯過程中會出現如下“對foo未定義的引用“的錯誤:
于是乎,趕緊引經據典,經過一番折騰之後,在https://groups.google.com/forum/#!topic/golang-nuts/O4RTszIyL7c最終找到了答案:
我們不需要手動地給go提供動态連結庫,甚至于go根本不認識我們自己手動編譯出的動态連結庫。其實cgo提供了一種機制:它能夠根據import”C”中引入的頭檔案,自動找到相應的源檔案進行編譯連結。這種機制的調用,需要用到go build指令。
輸出結果如下:
佛曰:衆生皆幻象,衆生皆平等!