此例子來自於go源碼中,借此來和大家分享一下兩者如何調用,網上很多文章語言不詳,也沒有一個完整的測試例子
首先src 目錄下有
testcgowin目錄下:
這裡的_obj目錄是cgo生成的
這裡需要展示的是go中如何調用c語言導出函數,以及在c語言中如何調用go的導出函數.
關鍵是cthread.go和cthread_windows.c兩個文件
cthread.go內容:
package ctestcgowin
// extern void doAdd(int, int);
import "C"
import (
"sync"
"fmt"
)
var sum struct {
sync.Mutex
i int
}
//export Add
func Add(x int) {
defer func() {
recover()
}()
sum.Lock()
sum.i += x
sum.Unlock()
var p *int
*p = 2
}
func TestCthread() {
sum.i = 0
C.doAdd(10, 6)
want := 10 * (10 - 1) / 2 * 6
if sum.i != want {
fmt.Printf("sum=%d, want %d\n", sum.i, want)
}
fmt.Println("want=",want)
}
這裡的:
// extern void doAdd(int, int);
import "C"
這兩行非常關鍵,必須緊挨著,不能有空行,而且要緊跟著package語句,import要單獨寫
這裡的注釋相當於c語言聲明了一個函數,你用#include當然也可以。遵循的都是c的語法,少個分號都是會報錯的。
然後是下面兩行:
//export Add
func Add(x int) {
export Add表示這是go要導出的一個函數,這樣c裡面可以調用。
如果此行注釋刪掉,c文件將會提示找不到Add函數。
cthread_windows.c:18: undefined reference to `Add'
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
#include "_cgo_export.h"
__stdcall
static unsigned int
addThread(void *p)
{
int i, max;
max = *(int*)p;
for(i=0; i<max; i++)
Add(i);
return 0;
}
void
doAdd(int max, int nthread)
{
enum { MaxThread = 20 };
int i;
uintptr_t thread_id[MaxThread];
if(nthread > MaxThread)
nthread = MaxThread;
for(i=0; i<nthread; i++)
thread_id[i] = _beginthreadex(0, 0, addThread, &max, 0, 0);
for(i=0; i<nthread; i++) {
WaitForSingleObject((HANDLE)thread_id[i], INFINITE);
CloseHandle((HANDLE)thread_id[i]);
}
}
我不曉得這個宏WIN32_LEAN_AND_MEAN什麼意思,跟著寫就行了,也沒有去查閱文檔以及代碼。
這裡doAdd是導出函數,addThread不需要導出,所以加了static,
#include "_cgo_export.h"是因為我們需要調用go的導出函數Add,有興趣的可以看看_obj目錄
到此為止,相互之間的關系已經說明白了,當然go與c語言之間的類型轉換,留作以後再說。
接下來如果想要利用這個lib,很簡單,
運行cgo生成必要的文件,然後go install將編譯生成testcgowin.a文件,此文件在pkg\windows_386目錄下
直接看testcgowin.go文件內容即可:
package main
import "testcgowin"
func main(){
ctestcgowin.TestCthread();
}
c和go互相調用的關鍵都是通過注釋實現的,並且cgo會自己編譯相應的.c文件,不需要特別說明,只需要放到相應目錄下即可。
總的來說go為了和c互操作做了很多,雖然沒法像c++那麼方便,但是基本上來收還是很順利的。