Используя GNAT Ada и Gnu C ++, я связываю кусок кода Ada с оболочкой c ++ и хотел бы правильно перехватывать исключения Ada при выполнении этого (глупого) кода:
with ada.text_io;
package body ada_throw is
procedure ada_throw is
begin
ada.text_io.put_line ("hello");
raise program_error;
end ada_throw;
end ada_throw;
соответствующий код спецификации:
package ada_throw is
procedure ada_throw;
pragma export (convention => C, entity => ada_throw, external_name => "ada_throw");
end ada_throw;
Делая это на стороне C ++:
#include <iostream>
extern "C"{
void ada_throw();
void adainit();
}
int main()
{
adainit();
ada_throw();
std::cout << "end of program" << std::endl;
return 0;
}
Я получаю это:
hello
raised PROGRAM_ERROR : ada_throw.adb:8 explicit raise
Так что механизм исключений работает, я не получаю последний отпечаток моей программы на C ++, и код возврата не равен нулю.
Теперь хочу ловить исключение. Если я использую catch(...)
это работает, но я больше не могу получить явное сообщение об ошибке, поэтому я попробовал это:
#include <iostream>
#include <cxxabi.h>
extern "C"{
void ada_throw();
void adainit();
}
int main()
{
adainit();
try
{
ada_throw();
}
catch (abi::__foreign_exception const &e)
{
std::cout << "exception" << std::endl;
}
std::cout << "end of program" << std::endl;
return 0;
}
работает нормально, получаю:
hello
exception
end of program
Единственный улов в том, что abi::__foreign_exception
не имеет what()
метод, поэтому я не могу получить осмысленное сообщение об ошибке.
И отладка программы, чтобы попытаться взломать e
это также тупик, так как это просто нулевой указатель с правильным типом:
(gdb) p &e
$2 = (const __cxxabiv1::__foreign_exception *) 0x0
Есть ли способ получить его из C ++?
В Ada вы можете получить информацию о возникновении исключения, используя функции Ada.Exceptions.Exception_Name
а также Ada.Exceptions.Exception_Message
, которые являются частью стандартной библиотеки. Один из вариантов — обеспечить тонкую привязку к этим двум функциям и вызывать их, когда вам нужна информация об исключении. (Точно, как карта abi::__foreign_exception
в Ada.Exceptions.Exception_ID
оставлено в качестве упражнения для читателя.)
Другой вариант — сделать явным для компилятора Ada, что вы пишете C ++ с другой стороны, и использовать CPlusPlus
вместо C
как ваше соглашение об экспорте. Это может заставить компилятор предоставлять исключения, которые понимает C ++.
Это только частичный ответ, так как я очень плохо разбираюсь в C ++, но я надеюсь, что он поможет вам в правильном направлении.
В зависимости от того, что вы хотите сделать с исключением в мире C ++, может быть проще / чище написать оболочку в Ada, которая вызывает ada_throw
и обрабатывает любые исключения. Затем просто вызовите эту обертку из C ++.
Если код C ++ должен видеть исключение и знать, что происходит, оболочка может предоставить what()
аналогичный метод, и повторно вызвать то же самое или новое (пользовательское) исключение.