此例子来自于go源码中,借此来和大家分享一下两者如何调用,网上很多文章语言不详,也没有一个完整的测试例子
首先src 目录下有
testcgowin目录下:
这里的_obj目录是cgo生成的
这里需要展示的是go中如何调用c语言导出函数,以及在c语言中如何调用go的导出函数.
关键是cthread.go和cthread_windows.c两个文件
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'
// 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++那么方便,但是基本上来收还是很顺利的。
|
请发表评论