如何在Golang中使用C++
如何在Golang中使用C++ 有一个开源库:https://github.com/infinispan/cpp-client,我需要用 Go 语言为其编写一个包装器。 该库包含“C 头文件”,并且库本身是用 C++ 编写的。
我不想使用“SWIG”。
我使用的是 Windows 10 操作系统,并已安装 gcc 和 g++。
2 回复
无法直接从Go调用C++代码。如果你不想使用SWIG,那么你需要编写自己的C函数来封装你需要调用的C++函数,然后从Go调用这些C函数。这个例子在Go Playground上无法运行,因为它似乎不支持cgo(或者我只是不知道如何启用它),但如果你将其保存到计算机上并分离文件,它是可以工作的:https://play.golang.org/p/bBoAxJd1eZf
func main() {
fmt.Println("hello world")
}
更多关于如何在Golang中使用C++的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中调用C++代码可以通过C语言层进行封装。以下是具体实现步骤:
1. 创建C语言包装头文件
// wrapper.h
#ifdef __cplusplus
extern "C" {
#endif
// 导出C接口函数
void* create_client(const char* host, int port);
void destroy_client(void* client);
int put_data(void* client, const char* key, const char* value);
char* get_data(void* client, const char* key);
int remove_data(void* client, const char* key);
#ifdef __cplusplus
}
#endif
2. 实现C++包装层
// wrapper.cpp
#include "wrapper.h"
#include "infinispan/hotrod/ConfigurationBuilder.h"
#include "infinispan/hotrod/RemoteCacheManager.h"
#include "infinispan/hotrod/RemoteCache.h"
using namespace infinispan::hotrod;
extern "C" {
void* create_client(const char* host, int port) {
ConfigurationBuilder builder;
builder.addServer().host(host).port(port);
RemoteCacheManager* cacheManager = new RemoteCacheManager(builder.build(), false);
cacheManager->start();
return static_cast<void*>(cacheManager);
}
void destroy_client(void* client) {
RemoteCacheManager* cacheManager = static_cast<RemoteCacheManager*>(client);
cacheManager->stop();
delete cacheManager;
}
int put_data(void* client, const char* key, const char* value) {
try {
RemoteCacheManager* cacheManager = static_cast<RemoteCacheManager*>(client);
RemoteCache<std::string, std::string> cache = cacheManager->getCache<std::string, std::string>();
cache.put(key, value);
return 0;
} catch (...) {
return -1;
}
}
char* get_data(void* client, const char* key) {
try {
RemoteCacheManager* cacheManager = static_cast<RemoteCacheManager*>(client);
RemoteCache<std::string, std::string> cache = cacheManager->getCache<std::string, std::string>();
std::string value = cache.get(key);
char* result = new char[value.length() + 1];
strcpy(result, value.c_str());
return result;
} catch (...) {
return nullptr;
}
}
int remove_data(void* client, const char* key) {
try {
RemoteCacheManager* cacheManager = static_cast<RemoteCacheManager*>(client);
RemoteCache<std::string, std::string> cache = cacheManager->getCache<std::string, std::string>();
cache.remove(key);
return 0;
} catch (...) {
return -1;
}
}
}
3. Go语言调用层
// infinispan.go
package infinispan
/*
#cgo CXXFLAGS: -std=c++11
#cgo LDFLAGS: -L${SRCDIR}/lib -lcppclient -lhotrod-client -lssl -lcrypto -lpthread
#include "wrapper.h"
#include <stdlib.h>
*/
import "C"
import (
"unsafe"
)
type Client struct {
ptr unsafe.Pointer
}
func NewClient(host string, port int) *Client {
chost := C.CString(host)
defer C.free(unsafe.Pointer(chost))
ptr := C.create_client(chost, C.int(port))
return &Client{ptr: ptr}
}
func (c *Client) Close() {
C.destroy_client(c.ptr)
}
func (c *Client) Put(key, value string) error {
ckey := C.CString(key)
cvalue := C.CString(value)
defer C.free(unsafe.Pointer(ckey))
defer C.free(unsafe.Pointer(cvalue))
result := C.put_data(c.ptr, ckey, cvalue)
if result != 0 {
return errors.New("put operation failed")
}
return nil
}
func (c *Client) Get(key string) (string, error) {
ckey := C.CString(key)
defer C.free(unsafe.Pointer(ckey))
cvalue := C.get_data(c.ptr, ckey)
if cvalue == nil {
return "", errors.New("get operation failed")
}
defer C.free(unsafe.Pointer(cvalue))
return C.GoString(cvalue), nil
}
func (c *Client) Remove(key string) error {
ckey := C.CString(key)
defer C.free(unsafe.Pointer(ckey))
result := C.remove_data(c.ptr, ckey)
if result != 0 {
return errors.New("remove operation failed")
}
return nil
}
4. 编译和链接
创建Makefile或构建脚本:
# Makefile
CXX = g++
GO = go
CXXFLAGS = -std=c++11 -fPIC -I/path/to/infinispan/include
LDFLAGS = -shared -L/path/to/infinispan/lib -lhotrod-client -lssl -lcrypto -lpthread
all: libwrapper.so wrapper.a
libwrapper.so: wrapper.cpp wrapper.h
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ wrapper.cpp
wrapper.a: wrapper.cpp wrapper.h
$(CXX) $(CXXFLAGS) -c wrapper.cpp -o wrapper.o
ar rcs $@ wrapper.o
clean:
rm -f *.o *.so *.a
5. 使用示例
// main.go
package main
import (
"fmt"
"log"
"./infinispan"
)
func main() {
client := infinispan.NewClient("localhost", 11222)
defer client.Close()
err := client.Put("key1", "value1")
if err != nil {
log.Fatal(err)
}
value, err := client.Get("key1")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Got value: %s\n", value)
err = client.Remove("key1")
if err != nil {
log.Fatal(err)
}
}
关键注意事项:
- 内存管理:C++分配的内存需要在Go中正确释放
- 异常处理:C++异常需要转换为C错误码
- 类型转换:注意Go字符串与C字符串的转换
- 线程安全:确保C++客户端是线程安全的
- 编译依赖:需要正确链接所有C++库依赖
这种方法通过C语言层封装C++接口,避免了Go直接调用C++的复杂性,同时保持了类型安全和内存管理的可控性。

