You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Rust库触发的Panic捕获为C++可捕获的异常?

问题

测试一个会触发Panic的Rust库并通过C调用,但无法在C中捕获Rust产生的Panic。相关代码及运行情况如下:

Rust库配置与代码

Cargo.toml

[package]
name = "boom"
version = "0.1.0"
edition = "2018"

[dependencies]
libc = "0.2"

[lib]
crate-type=["staticlib"]

src/lib.rs

#[no_mangle]
pub extern "C" fn boom() {
    panic!("Oh no, something went wrong!");    
}

C++初始调用代码

// g++ -g boom.cpp -L./target/debug -lboom -o boom

extern "C" {
    void boom();
}

int main() {
    boom();
}

运行结果:

thread '<unnamed>' panicked at src/lib.rs:3:5:
Oh no, something went wrong!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: failed to initiate panic, error 5

尝试捕获Panic的C++代码

// g++ -g boom.cpp -L./target/debug -lboom -o boom

#include <stdexcept>

extern "C" {
    void boom();
}

int main() {
    try
    {
      boom();
    }
    catch(const std::exception& e)
    {
      printf("exception captured\n");
    }
}

运行结果与之前一致,无法捕获Panic。请问是否有方法在C中捕获Rust库产生的Panic?或能否将Rust Panic转换为C可捕获的异常?


解决方案

Rust的Panic与C异常是完全独立的底层机制,**无法直接在C中捕获Rust Panic**。要实现跨语言错误处理,必须在Rust侧做转换处理,常见方案有两种:

方案1:捕获Panic并返回C风格错误码

修改Rust代码,用std::panic::catch_unwind捕获Panic,将其转换为C语言可识别的整数错误码:

修改后的src/lib.rs

use std::panic;
use libc::c_int;

#[no_mangle]
pub extern "C" fn boom() -> c_int {
    match panic::catch_unwind(|| {
        panic!("Oh no, something went wrong!");
    }) {
        Ok(_) => 0, // 无错误
        Err(_) => 1, // 捕获到Panic,返回错误码
    }
}

对应的C++调用代码:

// g++ -g boom.cpp -L./target/debug -lboom -o boom

#include <stdio.h>

extern "C" {
    int boom();
}

int main() {
    int ret = boom();
    if (ret != 0) {
        printf("Rust Panic captured via error code\n");
    }
    return 0;
}

方案2:将Panic转换为C++异常

如果希望用C的try/catch捕获,可在Rust侧捕获Panic后,调用C函数主动抛出异常(注意:该方法依赖编译器的异常实现,可移植性有限):

修改后的src/lib.rs

use std::panic;
use libc::{c_char};
use std::ffi::CString;

extern "C" {
    fn throw_cpp_exception(msg: *const c_char);
}

#[no_mangle]
pub extern "C" fn boom() {
    let result = panic::catch_unwind(|| {
        panic!("Oh no, something went wrong!");
    });

    if let Err(panic_msg) = result {
        // 将Panic消息转换为C字符串
        let msg = panic_msg.downcast_ref::<String>()
            .map(|s| CString::new(s.clone()).unwrap())
            .unwrap_or_else(|| CString::new("Unknown panic").unwrap());
        
        // 调用C++函数抛出异常
        unsafe {
            throw_cpp_exception(msg.as_ptr());
        }
    }
}

对应的C++代码:

// g++ -g boom.cpp -L./target/debug -lboom -o boom

#include <stdio.h>
#include <stdexcept>
#include <cstring>

extern "C" {
    void boom();
    
    // 供Rust调用的异常抛出函数
    void throw_cpp_exception(const char* msg) {
        throw std::runtime_error(msg ? msg : "Unknown panic");
    }
}

int main() {
    try
    {
        boom();
    }
    catch(const std::exception& e)
    {
        printf("Exception captured: %s\n", e.what());
    }
    return 0;
}

注意事项

  • catch_unwind无法捕获所有Panic:例如调用std::process::abort()或栈溢出引发的Panic,这类情况会直接终止程序,无法被捕获。
  • 跨语言异常的兼容性:方案2依赖C++编译器的异常实现(如GCC的__cxa_throw),不同平台或编译器可能存在兼容性问题,生产环境优先推荐方案1的错误码方式。

内容的提问来源于stack exchange,提问作者fgalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 19:03:12