好的,所以我需要-fexceptions
来允许C ++异常通过C代码传播。我试图比较C ++和C的结果,并且从我可以看出,编译的例程在程序集中是相同的,即使没有该选项[1]。这是测试:
#include <unistd.h>
typedef int (*Callback)(void* param,void* buffer,int n);
void write_wrapper(int fd,const void* buffer,int n)
{
const char* temp=(const char*)buffer;
while(n!=0)
{
int k=write(fd,temp,n);
n-=k;
temp+=k;
}
}
int test(Callback cb,void* cb_param)
{
char buffer[1024];
int n=0;
do
{
n=cb(cb_param,buffer,1024);
write_wrapper(STDOUT_FILENO,buffer,n);
}
while(n!=1024);
}
int test2(Callback cb,void* cb_param)
{
char more_stack_space_please[1024]={0};
cb(cb_param,more_stack_space_please,1024);
write_wrapper(STDOUT_FILENO,more_stack_space_please,1024);
test(cb,cb_param);
}
这里,调用者可以释放资源,所以即使回调函数抛出异常也不应该泄漏。
即使此示例似乎有效(使用简单的C ++驱动程序测试)
#include "lib.h"
#include <cstdio>
class Resource
{
public:
Resource()
{fprintf(stderr,"A Resource\n");}
~Resource()
{fprintf(stderr,"Not a Resource\n");}
};
int main()
{
try
{
Resource foo;
test([](void* cb_param,void* buffer, int n)->int
{
Resource bar;
throw "test";
},nullptr);
test2([](void* cb_param,void* buffer, int n)->int
{
throw "test2";
},nullptr);
}
catch(const char* err)
{
fprintf(stderr,"Error: %s\n",err);
return -1;
}
return 0;
}
,我从GTK回调中得到了未捕获的异常错误。我的想法:
答案 0 :(得分:8)
这个问题的问题在于,它询问未定义结果的定义行为是什么。
C标准没有描述通过C函数抛出异常时的行为,因为它不应该发生。
C ++标准没有解释通过C函数丢弃未捕获异常的机制,因为它不应该发生。
Windows Visual C ++使用fs:segment寄存器进行线程本地存储,并使用线程本地数据段中的特定插槽来创建catch帧的链接列表。
当抛出C ++异常时,会检查链表以查找堆栈对象的析构函数和合适的catch框架。
C编译器可能不知道这些资源的C ++用法,并且能够为不同目的重新使用这些插槽。如果插槽用于不兼容的功能,则会发生崩溃。
特定的平台和编译器可能会支持这一点,但您可能会在平台上随心所欲。
gcc是一个C编译器,因此不会抛出异常。它可以创建异常感知的代码,因为它支持-fexception
。
gnu compiler : using exceptions 建议使用-fexceptions编译C代码并说
特别是,展开到没有异常处理数据的帧将导致运行时中止。
虽然该语句的上下文没有描述是由于被调试子句,还是由于异常机制识别非法状态并导致中止。
实际的实现是硬件和操作系统特定的,在问题中没有指定,对于特定的答案,应该指定这些。
extern "C"
包装器来确保C是安全的,确保它是完全C ++编译单元