《GO语言高级编程》设计中案例,仅作为笔记进行收藏。CGO是C语⾔和Go语⾔之间的桥梁,原则上⽆法直接⽀持C++的类。CGO不⽀持C++语法的根本原因是C++⾄今为⽌还没有⼀个⼆进制接⼝规范(ABI)。⼀个C++类的构造函数在编译为⽬标⽂件时如何⽣成链接符号名称、⽅法在不同平台甚⾄是C++的不同版本之间都是不⼀样的。但是C++是兼容C语⾔,所以我们可以通过增加⼀组C语⾔函数接⼝作为C++类和CGO之间的桥梁,这样就可以间接地实现C++和Go之间的互联。当然,因为CGO只⽀持C语⾔中值类型的数据类型,所以我们是⽆法直接使⽤C++的引⽤参数等特性的。
- 准备一个C++类
// my_buffer.h
#include <string>
struct MyBuffer {
std::string* s_;
MyBuffer(int size) {
this->s_ = new std::string(size, char('\0'));
}
~MyBuffer() {
delete this->s_;
}
int Size() const {
return this->s_->size();
}
char* Data() {
return (char*)this->s_->data();
}
};
- 用纯C函数接口封装C++类
// my_buffer_capi.h
typedef struct MyBuffer_T MyBuffer_T;
MyBuffer_T* NewMyBuffer(int size);
void DeleteMyBuffer(MyBuffer_T* p);
char* MyBuffer_Data(MyBuffer_T* p);
int MyBuffer_Size(MyBuffer_T* p);
// my_buffer_capi.cc
#include "./my_buffer.h"
extern "C" {
#include "./my_buffer_capi.h"
}
struct MyBuffer_T: MyBuffer {
MyBuffer_T(int size): MyBuffer(size) {}
~MyBuffer_T() {}
};
MyBuffer_T* NewMyBuffer(int size) {
auto p = new MyBuffer_T(size);
return p;
}
void DeleteMyBuffer(MyBuffer_T* p) {
delete p;
}
char* MyBuffer_Data(MyBuffer_T* p) {
return p->Data();
}
int MyBuffer_Size(MyBuffer_T* p) {
return p->Size();
}
- 将纯C接口函数转为Go函数
// my_buffer_capi.go
package main
/*
#cgo CXXFLAGS: -std=c++11
#include "my_buffer_capi.h"
*/
import "C"
type cgo_MyBuffer_T C.MyBuffer_T
func cgo_NewMyBuffer(size int) *cgo_MyBuffer_T {
p := C.NewMyBuffer(C.int(size))
return (*cgo_MyBuffer_T)(p)
}
func cgo_DeleteMyBuffer(p *cgo_MyBuffer_T) {
C.DeleteMyBuffer((*C.MyBuffer_T)(p))
}
func cgo_MyBuffer_Data(p *cgo_MyBuffer_T) *C.char {
return C.MyBuffer_Data((*C.MyBuffer_T)(p))
}
func cgo_MyBuffer_Size(p *cgo_MyBuffer_T) C.int {
return C.MyBuffer_Size((*C.MyBuffer_T)(p))
}
- 包装为Go对象
// my_buffer.go
package main
import "unsafe"
type MyBuffer struct {
cptr *cgo_MyBuffer_T
}
func NewMyBuffer(size int) *MyBuffer {
return &MyBuffer{
cptr: cgo_NewMyBuffer(size),
}
}
func (p *MyBuffer) Delete() {
cgo_DeleteMyBuffer(p.cptr)
}
func (p *MyBuffer) Data() []byte {
data := cgo_MyBuffer_Data(p.cptr)
size := cgo_MyBuffer_Size(p.cptr)
return ((*[1 << 31]byte)(unsafe.Pointer(data)))[0:int(size):int(size)]
}
- main
// main
package main
//#include <stdio.h>
import "C"
import "unsafe"
func main() {
buf := NewMyBuffer(1024)
defer buf.Delete()
copy(buf.Data(), []byte("hello\x00"))
C.puts((*C.char)(unsafe.Pointer(&(buf.Data()[0]))))
}