好的,所以我需要 -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 回调中得到了未捕获的异常错误。我的想法:
- GTK 是一个共享库,所以它可能只影响链接器,而不影响代码生成器
- GTK(和 GLib)包含很多奇怪的 hack,可能会把事情搞砸
最佳答案
这个问题的问题是,它询问未定义结果的定义行为是什么。
C 标准没有描述通过 C 函数抛出异常时的行为,因为它不应该发生。
C++ 标准没有解释通过 C 函数丢弃未捕获异常的机制,因为它不应该发生。
实例
Windows Visual C++ 使用 fs: 段寄存器用于线程本地存储,并使用线程本地数据段中的特定槽来创建捕获帧的链表。
当抛出 C++ 异常时,将检查链表以查找堆栈对象的析构函数和合适的捕获帧。
C 编译器可能不知道这些资源的 C++ 使用情况,并且能够为不同的目的重新使用这些槽。如果插槽用于不兼容的功能,则会发生崩溃。
一个特定的平台和编译器可能支持这个,但你会随心所欲地为这样的平台。
gcc 是一个 C 编译器,因此不会抛出异常。它可以创建异常感知代码,因为它支持 -fexception
。
gnu compiler : using exceptions 建议用 -fexceptions 编译 C 代码并说
In particular, unwinding into a frame with no exception handling data will cause a runtime abort.
尽管该语句的上下文没有说明这是由于正在调试子句还是由于异常机制识别非法状态并导致中止。
实际的实现是特定于硬件和操作系统的,问题中没有具体说明,对于具体的答案,应该具体说明。
- C++ 没有兼容性 ABI。通过使用不同编译器编译的 C++ 对象进行调用并不能保证工作正常。
- 不建议在不同模块之间抛出异常,因为即使在编译器上的实现也会产生版本内不兼容的代码。
- 假设您可以控制 C 和 C++ 代码,通过启用异常并可能将 C 编译为 C++(使用
extern "C"
包装器,确保它是一个完整的 C++ 编译单元。
关于c++ - *什么时候* C++ 异常会破坏 C 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46183007/