如何在 C 中引发异常?

我在谷歌上输入了这个,但是我只在 C + + 中找到了 how-to。

我怎么能用 C 语言做呢?

179735 次浏览

C 语言中没有例外。在 C 语言中,错误通过函数的返回值、进程的退出值、发送给进程的信号(程序错误信号(GNU libc))或 CPU 硬件中断(如果有其他通知错误,则来自 CPU)(处理器如何处理除以零的情况)来通知。

但是,异常是在 C + + 和其他语言中定义的。异常处理是在 C + + 标准“ S.15异常处理”中规定的,在 C 标准中没有相应的部分。

C 语言没有例外。

有各种拙劣的实现尝试这样做(例如: http://adomas.org/excc/)。

普通的旧 C 实际上不支持异常。

您可以使用其他错误处理策略,例如:

  • 返回错误代码
  • 返回 FALSE并使用 last_error变量或函数。

参见 http://en.wikibooks.org/wiki/C_Programming/Error_handling

C 不支持异常。您可以尝试使用 Visual Studio 或 G + + 将您的 C 代码编译为 C + + ,然后看看它是否会按原样编译。大多数 C 应用程序将以 C + + 的形式编译,不需要进行重大更改,然后您可以使用 try... catch 语法。

在带有 Microsoft Visual C + + (MSVC)的 Windows 上有 __try ... __except ...,但它真的很可怕,如果可以避免的话,你不想使用它。最好说没有例外。

在 C 语言中,可以使用 setjmp()longjmp()函数的组合,在 setjmp.h.来自维基百科的例子中定义

#include <stdio.h>
#include <setjmp.h>


static jmp_buf buf;


void second(void) {
printf("second\n");         // prints
longjmp(buf,1);             // jumps back to where setjmp
//   was called - making setjmp now return 1
}


void first(void) {
second();
printf("first\n");          // does not print
}


int main() {
if ( ! setjmp(buf) ) {
first();                // when executed, setjmp returns 0
} else {                    // when longjmp jumps back, setjmp returns 1
printf("main");         // prints
}


return 0;
}

注意: 我实际上建议你 没有使用它们,因为它们在 C + + 中工作得很糟糕(本地对象的析构函数不会被调用) ,而且真的很难理解发生了什么。而是返回某种错误。

C 语言中没有 内置的异常机制; 您需要 模拟异常及其语义。这通常是依靠 setjmplongjmp来实现的。

有相当多的库,我正在实现另一个。它叫 例外,便携且免费。你可以看看它,并与 其他选择进行比较,看看哪个最适合你。

这个问题非常古老,但是我只是偶然发现了它,并且认为我应该分享一个技巧: 除以零,或者取消引用一个空指针。

问题只是“如何抛出”,而不是如何捕捉,甚至如何抛出特定类型的异常。很久以前,我遇到过这样的情况: 我们需要触发一个来自 C 的异常,以便在 C + + 中捕获它。具体来说,我们偶尔会收到“纯虚函数调用”错误的报告,并且需要说服 C 运行时的 _ purecrefunction 抛出一些东西。所以我们添加了我们自己的除以0的 _ puretrefunction,然后,我们得到了一个异常,我们可以在 C + + 上捕捉到它,甚至可以使用一些堆栈乐趣来查看哪里出错了。

正如在许多线程中提到的,这样做的“标准”方法是使用 setjmp/longjmp。我又发布了另一个这样的解决方案到“一个 href =”https://github.com/psevon/ 例外-and-raii-in-c”rel = “ nofollow”> https://github.com/psevon/exceptions-and-raii-in-c 据我所知,这是唯一依赖于自动清理已分配资源的解决方案。它实现了唯一和共享的智能指针,并允许中间函数允许异常通过而不捕获,并且仍然可以正确地清理它们在本地分配的资源。

C 能够抛出 C + + 异常,反正是机器代码。

例如,在文件 Barc中:

#include <stdlib.h>
#include <stdint.h>


extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long


int bar1()
{
int64_t * p = (int64_t*)__cxa_allocate_exception(8);
*p = 1976;
__cxa_throw(p, &_ZTIl, 0);
return 10;
}

空调文件中,

#include <stdint.h>
#include <cstdio>
extern "C" int bar1();


void foo()
{
try
{
bar1();
}
catch(int64_t x)
{
printf("good %ld", x);
}
}


int main(int argc, char *argv[])
{
foo();
return 0;
}

编译:

gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out

输出

good 1976

Https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html 有更多关于 __cxa_throw的详细信息。

我不确定它是否是可移植的,我在 Linux 上用‘ gcc-4.8.2’测试了它。

如果您使用 快乐之路设计模式编写代码(例如,对于嵌入式设备) ,您可以使用操作符“ goto”模拟异常错误处理(AKA 延迟或最终模拟)。

int process(int port)
{
int rc;
int fd1;
int fd2;


fd1 = open("/dev/...", ...);
if (fd1 == -1) {
rc = -1;
goto out;
}


fd2 = open("/dev/...", ...);
if (fd2 == -1) {
rc = -1;
goto out;
}


// Do some with fd1 and fd2 for example write(f2, read(fd1))


rc = 0;


out:


//if (rc != 0) {
(void)close(fd1);
(void)close(fd2);
//}


return rc;
}

它实际上不是一个异常处理程序,但是它会在函数退出时提供一种处理错误的方法。

附注: 您应该注意只在相同或更深的范围内使用 goto,并且永远不要跳转变量声明。

埃里克 · 罗伯茨在 C 中实现异常。

接口和实现第四章作者: 汉森。

错误处理学科

在 C 中实现例外(详细介绍 E. Roberts 的文章)

在 C 语言中,我们不能使用 try case 来处理错误。 但是如果你可以使用 Windows.h,那么你就可以:

#include <stdio.h>
#include <Windows.h>
#include <setjmp.h>
jmp_buf Buf;


NTAPI Error_Handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
printf("co loi roi ban oi.!!!\r\n");
longjmp(Buf, 1);
}


void main()
{
AddVectoredExceptionHandler(1, Error_Handler);
int x = 0;
printf("start main\r\n");
if (setjmp(Buf) == 0)
{
int y = 1 / x;
}
printf("end main\r\n");
    

}