前提條件:
了解go語言和c語言的基本知識和基本用法。
一、什麼是cgo
簡單地說,cgo是在go語言中使用c語言**的一種方式。
二、為什麼要有cgo
c語言經過數十年發展,經久不衰,各個方面的開源**、閉源庫已經非常豐富。這無疑是一塊巨大的寶藏,對於一門現代程式語言而言,如何用好現成的c**就顯得極為重要。
三、如何使用
3.1 系統配置
要想使用cgo,你的計算機上必須有gcc,並且將gcc編譯器的可執行檔案所在的目錄新增到path這個環境變數中。例如,我的gcc.exe在c:\mingw64\bin下,所以,要把c:\mingw64\bin這個目錄新增到path。
3.2 c假包
我們知道,go語言以包為**的邏輯單元。如果要在go**中使用c**,也要為c**單獨設立乙個「包」並將其匯入:
import "c"
c是乙個假包,包的性質它一般也有。例如可以用「包名.符號名」的方式使用其中的變數或型別。
var n c.int
這行**,定義了乙個c語言int型別的變數,與用
var conn net.conn
定義乙個net.conn型別的變數沒什麼語法上的不同。
如果緊挨著import "c"這行上方,加入連續若干行注釋,在注釋中編寫c**,這些c**就作為c包的內容。例如:
int plusone(int n)
return n + 1;
import "c"
在go**中就可以呼叫plusone這個函式,再例如:
#include
import "c"
在go**中就可以呼叫標頭檔案stdio.h中的函式。
除此之外,還可以把你的c原始檔放到要使用它的go原始檔的同一目錄,然後在c包中包含(include)對應的標頭檔案。例如,我有c原始檔ys_origin.c和標頭檔案ys_origin.h,而我要在ys_origin.go中呼叫ys_origin.c中的函式,那麼,我可以這麼做:
include "ys_origin.h"
import "c"
func funcone(a int, b string) error ;
import "c"
func testarray() point_beta;
import "c"
func teststruct()
var pb c.point_beta
pb.x = 33
pb.y = -10
fmt.println(pb) //
4.6 聯合體
go中使用c的聯合體是比較少見的,而且稍顯麻煩,因為go將c的聯合體視為位元組陣列。比方說,下面的聯合體large_integer被視為[8]byte。
typedef long long;
typedef unsigned long dword;
typedef long long longlong;
typedef union _large_integer u;
longlong quadpart;
} large_integer, *plarge_integer;
所以,如果乙個c的函式的某個引數的型別為large_integer,我們可以給它乙個[8]byte型別的實參,反之亦然。
那麼,如果乙個c函式要求傳入乙個聯合體,我們應該構建乙個位元組陣列作為實參。
typedef long long;
typedef unsigned long dword;
typedef long long longlong;
typedef union _large_integer u;
longlong quadpart;
} large_integer, *plarge_integer;
void aaa(large_integer li)
li.u.lowpart = 1;
li.u.highpart = 4;
import "c"
func testunion() ,返回值都是乙個uintptr。它們雖然接受inte***ce{}型別的引數,但必須傳遞乙個go函式,而且傳入的go函式的返回值的大小(size)必須和uintptr相同。它們根據乙個go函式(記憶體中的一段資料),生成乙個c函式(記憶體中的另一段資料),並將這個c函式的首位址返回。兩者的不同點是,前者生成的c函式是符合__stdcall呼叫約定的,後者生成的c函式是符合__cdecl呼叫約定的。
在獲得函式的首位址之後,還不能直接把它傳給c函式,因為c的指向函式的指標在go中被視為*[0]byte,所以要轉換一下。
c**:
#include
#ifndef null
#define null ((void*)0)
#endif
typedef uintptr_t(__stdcall* girl_proc)(unsigned int);
typedef uintptr_t(__cdecl* girl_proc_cdecl)(unsigned int);
unsigned int func1(unsigned int n, girl_proc gp)
if (gp == null)
return 0;
return (unsigned int)((*gp)(n));
unsigned int func2(unsigned int n, girl_proc_cdecl gp)
if (gp == null)
return 0;
return (unsigned int)((*gp)(n));
go**:
func testcallback() {
f1 := syscall.newcallback(plusone)
f2 := syscall.newcallbackcdecl(plustwo)
var m uint32 = 20
var n uint32 = 80
// func1 __stdcall
fmt.println(c.func1(c.uint(m), (*[0]byte)(unsafe.pointer(f1)))) // 21
// func2 __cdecl
fmt.println(c.func2(c.uint(n), (*[0]byte)(unsafe.pointer(f2)))) // 82
func plusone(n uint32) uintptr {
return uintptr(n + 1)
func plustwo(n uint32) uintptr {
return uintptr(n + 2)
c.func1的第二個引數型別為函式,所以要傳入乙個*[0]byte。
五、綜合示例
正在寫。
六、練習
以後我會製作一些習題。
go語言 結構體及結構體指標
結構體 struct 是由一系列具有相同型別或不同型別的資料構成的資料集合,也叫結構。可以理解為其他程式語言中的類 結構體既可以定義在函式內,也可以定義在函式外,函式外為全域性結構體可以跨包訪問 前提是結構體首字母大寫 結構體變數是值型別,可以使用fmt.printf p 結構體變數 來檢視其記憶體...
C語言瘋狂講義 (十一)C語言動態記憶體及結構體
1 動態記憶體管理 記憶體分為5大區域 棧 存放區域性變數 堆 存放程式執行過程中,動態申請的空間 bss 未初始化的全部變數,和靜態變數 資料段 已經初始化的全域性變數和靜態變數常量 段 程式源 編譯生成的二進位制檔案 1 malloc void malloc size 動態的向記憶體申請連續的s...
C 結構體指標的定義及使用詳解
在解析c 結構體指標前,必須知道c 結構體是如何定義的。在c 中同樣定義該結構體。c 結構體指標之c 結構體的定義 structlayout layoutkind.sequential public struct vgastat 定義完結構體後,就可將接收到的c 結構體指標轉換為定義的結構體物件。v...