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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:27:43