看了下go往c里面设置回调函数的例子,里面的回调函数的参数都是简单的类型,char *和int,今天在此举一个结构体为回调参数的例子。
头文件为GoDll.h,内容如下:
#ifndef __GO_DLL_H__
#define __GO_DLL_H__
/*C代码头文件需要添加类似如下声明*/
typedef struct CMyCallBack_
{
int iLen;
char szVal[100];
}CMyCallBack;
typedef int (*fnc)(CMyCallBack* myCallBack); // 回调函数的名称为 fnc,参数是CMyCallBack *
void printHello();
void callBack(fnc f);
#endif
实现文件为GoDll.c,内容如下:
#include "GoDll.h"
#include <stdio.h>
#include <string.h>
void printHello()
{
printf("printHello\n");
}
void callBack(fnc f)
{
CMyCallBack myCallBack;
strcpy(myCallBack.szVal, "hello world");
myCallBack.iLen = strlen(myCallBack.szVal);
f(&myCallBack);
}
经过 gcc -fPIC -shared GoDll.c -o libGoDll.so
然后将libGoDll.so和GoDll.h拷贝到go目录下,写两个go文件,cfuns.go和main.go
其中cfuns.go的内容如下:
package main
/*
#include <stdio.h>
#include "GoDll.h"
// The gateway function
int printMyCallBack_cgo(CMyCallBack *myCallBack)
{
int printMyCallBack(int, char *);
printf("val is %s\n", myCallBack->szVal);
return printMyCallBack(myCallBack->iLen, (char *)myCallBack->szVal);
}
*/
import "C"
type MY_CALLBACK struct {
iLen int
strVal string
}
main.go的内容如下:
package main
/*
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L./ -lGoDll
#include "GoDll.h"
int printMyCallBack_cgo(CMyCallBack *myCallBack);
*/
import "C"
import (
"fmt"
"unsafe"
)
//export printMyCallBack
func printMyCallBack(iLen C.int, strVal *C.char) int {
fmt.Printf("len is %d\n", iLen);
fmt.Printf("value is %s\n", C.GoString(strVal));
return 0;
}
func main(){
fmt.Println("in main")
C.printHello()
C.callBack((C.fnc)(unsafe.Pointer(C.printMyCallBack_cgo)))
}
需要注意的地方:
1.func printMyCallBack上面的//export printMyCallBack不可少
2.int printMyCallBack_cgo(CMyCallBack *myCallBack);声明不可少
3.go语言的指针不能直接设置成C语言里面的回调函数指针,需要进行中转,比如上面的 printMyCallBack_cgo就是中转函数。
4.c语言里面能调用go函数,不过此go函数需要导出,比如上面的printMyCallBack就需要导出。
5.go函数并没有导出成下面这种样式
func printMyCallBack(myCallBack *C.CMyCallBack) int {
…
}
主要是因为CMyCallBack里面的char szVal[100];不好转换,用各种办法,一直转换出错。所以干脆拆开。