8分钟
2.8.2.2 导出C接口
我们前面仿照C++对象到C接口的过程,也抽象一组C接口描述Person对象。创建一个person_capi.h
文件,对应C接口规范文件:
// person_capi.h
#include <stdint.h>
typedef uintptr_t person_handle_t;
person_handle_t person_new(char* name, int age);
void person_delete(person_handle_t p);
void person_set(person_handle_t p, char* name, int age);
char* person_get_name(person_handle_t p, char* buf, int size);
int person_get_age(person_handle_t p);
然后是在Go语言中实现这一组C函数。
需要注意的是,通过CGO导出C函数时,输入参数和返回值类型都不支持const修饰,同时也不支持可变参数的函数类型。同时如内存模式一节所述,我们无法在C/C++中直接长期访问Go内存对象。因此我们使用前一节所讲述的技术将Go对象映射为一个整数id。
下面是person_capi.go
文件,对应C接口函数的实现:
// person_capi.go
package main
//#include "./person_capi.h"
import "C"
import "unsafe"
//export person_new
func person_new(name *C.char, age C.int) C.person_handle_t {
id := NewObjectId(NewPerson(C.GoString(name), int(age)))
return C.person_handle_t(id)
}
//export person_delete
func person_delete(h C.person_handle_t) {
ObjectId(h).Free()
}
//export person_set
func person_set(h C.person_handle_t, name *C.char, age C.int) {
p := ObjectId(h).Get().(*Person)
p.Set(C.GoString(name), int(age))
}
//export person_get_name
func person_get_name(h C.person_handle_t, buf *C.char, size C.int) *C.char {
p := ObjectId(h).Get().(*Person)
name, _ := p.Get()
n := int(size) - 1
bufSlice := ((*[1 << 31]byte)(unsafe.Pointer(buf)))[0:n:n]
n = copy(bufSlice, []byte(name))
bufSlice[n] = 0
return buf
}
//export person_get_age
func person_get_age(h C.person_handle_t) C.int {
p := ObjectId(h).Get().(*Person)
_, age := p.Get()
return C.int(age)
}
在创建Go对象后,我们通过NewObjectId将Go对应映射为id。然后将id强制转义为person_handle_t类型返回。其它的接口函数则是根据person_handle_t所表示的id,让根据id解析出对应的Go对象。
学员评价