Golang中从C++调用函数时遇到的段错误问题

Golang中从C++调用函数时遇到的段错误问题 使用 g++ 9.3.0 和 go 1.10.4

我想调用一个 Go 函数,让它打印一个由 C++ 输入的整数。

以下是设置:

在 Go 中:

//export OnLogin_1
func OnLogin_1(status C.int) {
	fmt.Println("target1 ok:", status)
}

在头文件中:

typedef void (*nfun)(int LoginStatus);
extern nfun OnLogin_1;

这表明有一个名为 OnLogin_1 的函数,它有一个整数参数。

然后在 cpp 文件中:

std::cout << "=====Login Succeeded @" << this->target << std::endl;
if(this->target==1)          OnLogin_1(1);

我看到了输出 =====Login Succeeded @1 以及下一行:Segment Error

我的代码有什么问题?提前感谢。


更多关于Golang中从C++调用函数时遇到的段错误问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你用来构建Go代码的命令是什么?

更多关于Golang中从C++调用函数时遇到的段错误问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


只需在代码目录中简单地执行 go build 命令,即可编译目录内的所有脚本文件,而不仅仅是单个文件。

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

这是一个典型的C/C++与Go之间函数指针调用约定不匹配的问题。问题在于你的C++代码试图直接调用Go导出的函数,但Go的调用约定与C++不同。

主要问题:

  1. Go导出的函数使用C调用约定,但你的C++代码声明为普通函数指针
  2. 缺少必要的//export指令和cgo导出声明

正确的解决方案:

Go端代码:

package main

/*
#include <stdint.h>

// C端声明
typedef void (*LoginCallback)(int32_t status);
extern void callLoginCallback(LoginCallback cb, int32_t status);
*/
import "C"
import (
	"fmt"
	"unsafe"
)

//export OnLogin_1
func OnLogin_1(status C.int32_t) {
	fmt.Println("target1 ok:", status)
}

// 导出的C函数,用于C++调用
//export GetLoginCallback
func GetLoginCallback() unsafe.Pointer {
	return unsafe.Pointer(C.LoginCallback(C.OnLogin_1))
}

func main() {
	// 保持程序运行
	select {}
}

C++头文件(callback.h):

#ifndef CALLBACK_H
#define CALLBACK_H

#include <cstdint>

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*LoginCallback)(int32_t status);

// 从Go获取函数指针
LoginCallback GetLoginCallback();

// 调用回调的辅助函数
void callLoginCallback(LoginCallback cb, int32_t status);

#ifdef __cplusplus
}
#endif

#endif // CALLBACK_H

C++实现文件:

#include "callback.h"
#include <iostream>

extern "C" {
    // 声明Go导出的函数
    LoginCallback GetLoginCallback();
}

class LoginHandler {
private:
    int target;
    LoginCallback callback;
    
public:
    LoginHandler(int t) : target(t) {
        // 从Go获取函数指针
        callback = GetLoginCallback();
    }
    
    void onLoginSucceeded() {
        std::cout << "=====Login Succeeded @" << this->target << std::endl;
        if(this->target == 1 && callback) {
            // 通过C函数调用Go回调
            callLoginCallback(callback, 1);
        }
    }
};

// C辅助函数的实现
extern "C" void callLoginCallback(LoginCallback cb, int32_t status) {
    if (cb) {
        cb(status);
    }
}

编译命令:

# 编译Go为C共享库
go build -buildmode=c-shared -o libcallback.so main.go

# 编译C++并链接
g++ -o main cpp_main.cpp -L. -lcallback -I.

关键点:

  1. Go函数必须通过//export指令显式导出
  2. 使用extern "C"确保C++使用C调用约定
  3. 通过中间C函数进行调用,避免直接调用Go函数指针
  4. 使用unsafe.Pointer进行函数指针的类型转换

这种段错误通常是因为调用约定不匹配或函数指针类型不正确导致的栈损坏。上述方案通过C接口层进行正确的调用约定转换。

回到顶部