ANSI C相当于try / catch?

时间:2010-09-21 16:56:59

标签: c++ c exception-handling try-catch ansi-c

我有一些我正在使用的C代码,当代码运行时我发现错误但是关于如何正确执行try / catch的信息很少(如在C#或C ++中)。

例如在C ++中,我只是这样做:

try{
//some stuff
}
catch(...)
{
//handle error
}

但在ANSI C中我有点迷失。我尝试了一些在线搜索,但是我没有看到关于如何实现这一点的足够信息/想想我会问这里以防万一有人能指出我正确的方向。

这是我正在使用的代码(相当简单,递归的方法),并希望用try / catch(或等效的错误处理结构)进行包装。

但是我的主要问题是如何在ANSI C中执行try / catch ...实现/示例不必是递归的。

void getInfo( int offset, myfile::MyItem * item )
{
    ll::String myOtherInfo = item->getOtherInfo();
    if( myOtherInfo.isNull() )
        myOtherInfo = "";
    ll::String getOne = "";
    myfile::Abc * abc = item->getOrig();
    if( abc != NULL )
    {
        getOne = abc->getOne();
    }
    for( int i = 0 ; i < offset ; i++ )
    {
             printf("found: %d", i);
    }
    if( abc != NULL )
        abc->release();
    int childCount = item->getChildCount();
    offset++;
    for( int i = 0 ; i < childCount ; i++ )
        getInfo( offset, item->getChild(i) );
    item->release();
}

8 个答案:

答案 0 :(得分:25)

一般来说,你没有。

可以使用setjmplongjmp来构建与try / catch非常相似的东西,尽管在C中没有像析构函数或堆栈展开这样的东西,所以RAII是不可能的。您甚至可以使用所谓的“清理堆栈”(参见例如Symbian / C ++)来近似RAII,尽管它不是非常接近的近似值,并且它需要做很多工作。

指示C中的错误或失败的常用方法是返回指示成功状态的值。呼叫者检查返回值并相应地采取行动。例如,请参阅标准C函数:printfreadopen,了解如何指定函数。

混合使用C和C ++代码时,必须确保C ++异常永远不会到达C代码。在编写将从C调用的C ++函数时,请抓住所有内容。

答案 1 :(得分:17)

C不支持异常处理。

有关此问题的一种方法的信息here。这显示了简单的setjmp/longjmp方法,但也提供了更为复杂的替代方案,深入讨论。

答案 2 :(得分:4)

有经典的展开goto模式:

FILE *if = fopen(...);
FILE *of = NULL;
if (if == NULL) return; 

of = fopen(...);
if (of == NULL) goto close_if;

/* ...code... */
if (something_is_wrong) goto close_of;

/* ... other code... */

close_of:
  fclose(of);
close_if:
  fclose(if);

return state;

或者,您可以通过隔离另一个函数中的“try”代码以有限的方式伪造它

int try_code(type *var_we_must_write, othertype var_we_only_read /*, ... */){
  /* ...code... */
  if (!some_condition) return 1;
  /* ...code... */
  if (!another_condition) return 2;
  /* ...code... */
  if (last_way_to_fail) return 4;
  return 0;
}

void calling_routine(){
  /* ... */
  if (try_code(&x,y/*, other state */) ) {
     /* do your finally here */
  }
 /* ... */
}

但两种方法都不完全等效。您必须自己管理所有资源,在找到处理程序之前不会自动回滚,等等......

答案 3 :(得分:4)

我喜欢使用的一种有用的编码风格如下。我不知道它是否有一个特定的名称,但当我将一些汇编代码反向工程到等效的C代码时,我遇到了它。你确实失去了缩进级别,但这对我来说并不是什么大问题。留意将指出无限循环的评论者! :)

int SomeFunction() {
    int err = SUCCESS;

    do {
        err = DoSomethingThatMayFail();
        if (err != SUCCESS) {
            printf("DoSomethingThatMayFail() failed with %d", err);
            break;
        }

        err = DoSomethingElse();
        if (err != SUCCESS) {
            printf("DoSomethingElse() failed with %d", err);
            break;
        }

        // ... call as many functions as needed.

        // If execution gets there everything succeeded!
        return SUCCESS;
    while (false);

    // Something went wrong!
    // Close handles or free memory that may have been allocated successfully.

    return err;
}

答案 4 :(得分:4)

这是我在C:exceptions4c中实现的异常处理系统。

它由宏构建,构建在setjmplongjmp之上,并且它是100%可移植的ANSI C.

There您还可以找到我所知道的所有不同实现的列表。

答案 5 :(得分:2)

您可以在本书中找到longjmp的可能实现:C Interfaces and Implementations: Techniques for Creating Reusable Software - David Hanson

您可以找到代码herehere作为本书中使用的样式的示例。

答案 6 :(得分:1)

如果您想进行多级跳转,请查看setjmp()longjmp()。它们可以用作原始异常抛出。 setjmp()函数设置返回位置,并返回状态值。 longjmp()函数转到返回位置,并提供状态值。您可以根据状态值在catch之后调用来创建setjmp()函数。

不管出于何种原因,不要在C ++中使用它们。它们不会进行堆栈展开或调用析构函数。

答案 7 :(得分:0)

由于C ++最初是作为C预处理器实现的,它有Try / Catch,你可以重做Bjarne Stroustrup的工作并编写一个预处理器来完成它。