Golang中CGO与C++绑定的实现探讨
Golang中CGO与C++绑定的实现探讨 我正在尝试用Go语言编译简单的C++代码,但遇到了一些错误:
// namespace test
// {
// int val = 500;
// }
//
import "C"
输出:error: unknown type name ‘namespace’
这很可能是因为编译器是针对C语言而不是C++的;我该如何更改这一点?
// #include <algorithm>
import "C"
输出:fatal error: algorithm: No such file or directory
包含文件存在,并且可以被g++找到;但Go编译器找不到该文件。我需要在这里更改什么?我不想手动包含每个文件夹。
这是一个位于/usr/include/c++/8/algorithm的C++头文件;这些头文件没有被包含是因为它是C语言而不是C++吗?
我已经看过howto-go-with-cpp,但这种变通方法对我的构建堆栈和使用的依赖项并不好,因为它需要修改包含的头文件。
Go版本:在树莓派上使用go1.11.6 linux/arm。
更多关于Golang中CGO与C++绑定的实现探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
另一个例子使用了我发布的链接中相同的技术:他们创建了一个额外的C头文件,并将C++文件编译为库,这正是我试图避免的。
更多关于Golang中CGO与C++绑定的实现探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中使用CGO调用C++代码需要特殊处理,因为CGO默认只支持C语言。以下是解决方案:
1. 启用C++支持
使用// #cgo CFLAGS:和// #cgo CXXFLAGS:指令启用C++编译:
// #cgo CXXFLAGS: -std=c++11
// #cgo LDFLAGS: -lstdc++
/*
#include <cstdio>
namespace test {
int val = 500;
}
extern "C" {
int getVal() {
return test::val;
}
}
*/
import "C"
import "fmt"
func main() {
fmt.Println(C.getVal()) // 输出: 500
}
2. 处理C++标准库头文件
对于<algorithm>等C++标准库头文件,需要使用C++兼容的包含方式:
// #cgo CXXFLAGS: -std=c++11 -I/usr/include/c++/8 -I/usr/include/arm-linux-gnueabihf/c++/8
// #cgo LDFLAGS: -lstdc++
/*
#include <algorithm>
#include <vector>
extern "C" {
void sortExample() {
std::vector<int> vec = {3, 1, 4, 1, 5};
std::sort(vec.begin(), vec.end());
}
int maxExample(int a, int b) {
return std::max(a, b);
}
}
*/
import "C"
func main() {
C.sortExample()
maxVal := C.maxExample(10, 20)
println(maxVal) // 输出: 20
}
3. 完整的C++类绑定示例
// #cgo CXXFLAGS: -std=c++11
// #cgo LDFLAGS: -lstdc++
/*
#include <cstdlib>
class Counter {
private:
int count;
public:
Counter() : count(0) {}
void increment() { count++; }
int get() { return count; }
};
// C包装函数
extern "C" {
Counter* createCounter() {
return new Counter();
}
void incrementCounter(Counter* c) {
c->increment();
}
int getCounter(Counter* c) {
return c->get();
}
void deleteCounter(Counter* c) {
delete c;
}
}
*/
import "C"
import (
"fmt"
"unsafe"
)
type Counter struct {
ptr unsafe.Pointer
}
func NewCounter() *Counter {
return &Counter{
ptr: unsafe.Pointer(C.createCounter()),
}
}
func (c *Counter) Increment() {
C.incrementCounter((*C.Counter)(c.ptr))
}
func (c *Counter) Get() int {
return int(C.getCounter((*C.Counter)(c.ptr)))
}
func (c *Counter) Close() {
C.deleteCounter((*C.Counter)(c.ptr))
c.ptr = nil
}
func main() {
counter := NewCounter()
defer counter.Close()
counter.Increment()
counter.Increment()
fmt.Println(counter.Get()) // 输出: 2
}
4. 针对树莓派的特定配置
对于ARM架构的树莓派,需要指定正确的包含路径:
// #cgo CXXFLAGS: -std=c++11 -I/usr/include/c++/8 -I/usr/include/arm-linux-gnueabihf/c++/8
// #cgo LDFLAGS: -lstdc++
/*
#include <iostream>
extern "C" {
void printHello() {
std::cout << "Hello from C++" << std::endl;
}
}
*/
import "C"
func main() {
C.printHello()
}
5. 构建命令
使用go build时,确保C++编译器可用:
# 设置C++编译器
export CXX=g++
export CC=gcc
# 构建
go build -x main.go
关键点:
- 必须使用
extern "C"包装C++函数,避免名称修饰 - 通过
// #cgo CXXFLAGS:指定C++编译标志 - 链接
-lstdc++标准C++库 - 对于C++类,需要在Go中创建包装结构体管理生命周期
- 使用
unsafe.Pointer处理C++对象指针

