go與c互相調用


此例子來自於go源碼中,借此來和大家分享一下兩者如何調用,網上很多文章語言不詳,也沒有一個完整的測試例子

  1. 目錄結構

首先src 目錄下有

testcgowin目錄下:

這里的_obj目錄是cgo生成的

這里需要展示的是go中如何調用c語言導出函數,以及在c語言中如何調用go的導出函數.

關鍵是cthread.go和cthread_windows.c兩個文件

  1. go文件

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'

  1. c語言文件

// 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語言之間的類型轉換,留作以后再說。

  1. 編譯生成.a文件

接下來如果想要利用這個lib,很簡單,

運行cgo生成必要的文件,然后go install將編譯生成testcgowin.a文件,此文件在pkg\windows_386目錄下

  1. 利用.a文件

直接看testcgowin.go文件內容即可:

package main
import "testcgowin"


func main(){
ctestcgowin.TestCthread();
}

 

  1. 結語

c和go互相調用的關鍵都是通過注釋實現的,並且cgo會自己編譯相應的.c文件,不需要特別說明,只需要放到相應目錄下即可。

總的來說go為了和c互操作做了很多,雖然沒法像c++那么方便,但是基本上來收還是很順利的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM