Golang中如何从C/C++调用包含字符串和map类型字段的结构体函数

Golang中如何从C/C++调用包含字符串和map类型字段的结构体函数 我们的需求是在C++代码中调用Golang库中的函数。目前我们正在使用 -buildmode=c-shared 构建库。

Golang库中的函数使用结构体作为输入和输出。例如:

type Request struct {
	X  string
	Y  string
	Z  map[string]string
}

如果我尝试使用C结构体,它不支持字符串和映射类型,这使事情变得复杂。 https://play.golang.org/p/Qjuu5j2nAv1

我们已经使用protobuf来序列化和反序列化这些复杂的结构体。是否有其他替代方案?因为使用protobuf使得在另一个Golang项目中将此共享Go源码作为库使用变得困难。


更多关于Golang中如何从C/C++调用包含字符串和map类型字段的结构体函数的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

map 是一个指针类型,因此你可以将 map[string]string 视为 C 语言中的 void *,然后在 Go 中编写一些简单的函数,并从 C 语言中调用这些函数来执行 GetPutKeys 等操作。这些函数接收一个 unsafe.Pointer 参数,将其转换为正确的 map 类型并执行相应的操作。

func main() {
    fmt.Println("hello world")
}

更多关于Golang中如何从C/C++调用包含字符串和map类型字段的结构体函数的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


一种可行的方案是使用CGO通过指针传递序列化数据,结合Go的反射机制在Go端重建结构体。以下是具体实现示例:

// export_request.go
package main

import (
	"C"
	"encoding/json"
	"unsafe"
)

// Request 结构体定义
type Request struct {
	X string            `json:"x"`
	Y string            `json:"y"`
	Z map[string]string `json:"z"`
}

//export ProcessRequest
func ProcessRequest(cData *C.char, cLen C.int) *C.char {
	// 将C字符串转换为Go字节切片
	goData := C.GoBytes(unsafe.Pointer(cData), cLen)
	
	// 反序列化JSON到Go结构体
	var req Request
	if err := json.Unmarshal(goData, &req); err != nil {
		return C.CString("")
	}
	
	// 处理请求(示例)
	req.X = "processed_" + req.X
	if req.Z == nil {
		req.Z = make(map[string]string)
	}
	req.Z["status"] = "completed"
	
	// 序列化结果
	result, _ := json.Marshal(req)
	return C.CString(string(result))
}

func main() {}

C++调用端示例:

// main.cpp
#include <iostream>
#include <cstring>

extern "C" {
    char* ProcessRequest(const char* data, int length);
}

int main() {
    // 准备JSON数据
    const char* json_data = R"({
        "x": "test1",
        "y": "test2",
        "z": {"key1": "value1"}
    })";
    
    // 调用Go函数
    char* result = ProcessRequest(json_data, strlen(json_data));
    
    std::cout << "Result: " << result << std::endl;
    
    // 释放Go返回的字符串
    free(result);
    return 0;
}

构建命令:

# 构建Go共享库
go build -buildmode=c-shared -o librequest.so export_request.go

# 编译C++程序
g++ -o main main.cpp -L. -lrequest

另一种方案是使用C结构体配合辅助函数:

// export_request2.go
package main

import "C"
import (
	"unsafe"
)

// C兼容的结构体
type CRequest struct {
	x *C.char
	y *C.char
	keys **C.char
	values **C.char
	count C.int
}

//export ProcessRequest2
func ProcessRequest2(req *CRequest) *C.char {
	// 转换字符串
	x := C.GoString(req.x)
	y := C.GoString(req.y)
	
	// 转换map
	z := make(map[string]string)
	if req.count > 0 {
		keys := unsafe.Slice(req.keys, int(req.count))
		values := unsafe.Slice(req.values, int(req.count))
		
		for i := 0; i < int(req.count); i++ {
			key := C.GoString(keys[i])
			value := C.GoString(values[i])
			z[key] = value
		}
	}
	
	// 创建Go结构体
	request := Request{
		X: x,
		Y: y,
		Z: z,
	}
	
	// 处理逻辑
	request.X = "modified_" + request.X
	
	// 返回结果(示例)
	return C.CString(request.X)
}

func main() {}

这些方案避免了protobuf的依赖,同时保持了Go结构体的完整性。JSON方案更通用,C结构体方案性能更好。

回到顶部