如何在C++处理程序中捕获Ada异常时获取异常信息?
如何在C++中获取Ada抛出的异常的错误信息?
我之前处理过类似的Ada与C跨语言交互的异常问题,你碰到的abi::__foreign_exception为空、无法获取具体错误信息的情况,本质是因为GNAT Ada的异常机制和C的异常系统并不直接兼容——跨语言传递的异常只会被标记为“外来异常”,不会自动携带Ada的异常描述信息到C++侧。
要解决这个问题,核心思路是在Ada端主动捕获异常,提取错误信息并转换成C兼容的格式暴露给C++,具体实现步骤如下:
步骤1:修改Ada代码,添加异常信息导出逻辑
我们需要在Ada代码里捕获抛出的异常,提取Exception_Message(或者更详细的Exception_Information),将其存储为C风格的字符串,并导出对应的访问、重置和内存释放函数。
Ada规范文件(ada_throw.ads)
with Interfaces.C; use Interfaces.C; package ada_throw is procedure ada_throw; pragma Export (Convention => C, Entity => ada_throw, External_Name => "ada_throw"); -- 获取最后一次Ada异常的错误信息(C风格字符串) function get_last_exception_message return chars_ptr; pragma Export (Convention => C, Entity => get_last_exception_message, External_Name => "get_last_exception_message"); -- 重置异常信息缓冲区,避免跨调用污染 procedure reset_exception_message; pragma Export (Convention => C, Entity => reset_exception_message, External_Name => "reset_exception_message"); -- 释放Ada端分配的异常信息内存 procedure free_exception_message(Msg : chars_ptr); pragma Export (Convention => C, Entity => free_exception_message, External_Name => "free_exception_message"); private Last_Exception_Msg : chars_ptr := Null_Ptr; end ada_throw;
Ada体文件(ada_throw.adb)
with Ada.Text_IO; with Ada.Exceptions; with Ada.Characters.Conversions; with Interfaces.C.Strings; package body ada_throw is use Ada.Exceptions; use Ada.Characters.Conversions; use Interfaces.C.Strings; procedure ada_throw is begin Ada.Text_IO.Put_Line ("hello"); -- 带描述信息抛出异常 raise Program_Error with "ada_throw.adb:8 explicit raise"; exception when E : others => -- 先释放之前的内存(如果有的话) if Last_Exception_Msg /= Null_Ptr then Free(Last_Exception_Msg); end if; -- 将Ada异常信息转换为C风格字符串 Last_Exception_Msg := New_String(Exception_Message(E)); -- 重新抛出异常,让C++可以捕获到 raise; end ada_throw; function get_last_exception_message return chars_ptr is begin return Last_Exception_Msg; end get_last_exception_message; procedure reset_exception_message is begin if Last_Exception_Msg /= Null_Ptr then Free(Last_Exception_Msg); Last_Exception_Msg := Null_Ptr; end if; end reset_exception_message; procedure free_exception_message(Msg : chars_ptr) is begin Free(Msg); end free_exception_message; end ada_throw;
步骤2:修改C++代码,捕获异常并获取信息
在C++端,我们需要声明Ada导出的函数,在调用Ada函数前重置异常信息,捕获异常后调用get_last_exception_message获取具体描述,并记得释放Ada端分配的内存。
#include <iostream> #include <cstring> extern "C" { void ada_throw(); void adainit(); void adafinal(); // 不要忘记清理Ada运行时资源 const char* get_last_exception_message(); void reset_exception_message(); void free_exception_message(const char* msg); } int main() { adainit(); reset_exception_message(); // 初始化异常信息缓冲区 try { ada_throw(); std::cout << "end of program" << std::endl; } catch (...) { const char* msg = get_last_exception_message(); if (msg && strlen(msg) > 0) { std::cout << "Caught Ada exception: " << msg << std::endl; free_exception_message(msg); // 释放Ada端分配的内存 } else { std::cout << "Caught unknown Ada exception" << std::endl; } std::cout << "end of program" << std::endl; } adafinal(); return 0; }
关键注意事项
- 内存管理:因为Ada和C使用不同的内存分配器,所以动态分配的字符串必须由Ada端提供的函数释放,不能在C里用
delete或free。 - 异常信息重置:每次调用Ada函数前要调用
reset_exception_message,避免上次的异常信息干扰当前调用的结果。 - 详细异常信息:如果需要包含栈跟踪等更详细的信息,可以用
Ada.Exceptions.Exception_Information代替Exception_Message,它会返回包含异常类型、位置和栈信息的字符串。 - Ada运行时清理:必须调用
adafinal()来清理Ada运行时的资源,避免内存泄漏。
这样修改后,你的C++程序就能正确输出Ada异常的具体错误信息了,运行结果会类似:
hello Caught Ada exception: raised PROGRAM_ERROR : ada_throw.adb:8 explicit raise end of program
内容的提问来源于stack exchange,提问作者Jean-François Fabre
相关产品推荐
相关产品推荐

