3

我是 C 新手,来自较新语言(如 Java 和 C++)的背景,我不确定如何处理运行时错误,例如发送给函数的不正确参数。

例如,假设我想编写一个函数来操作字符串(假设任何有效的 int 都是可接受的返回值):

int foo (char s[]) {
    if ( strlen(s) < 1)
        // ERROR
    ....
    ....
    return someInt;
}

如果我希望函数立即停止,如何在 Ansi C 中处理这种情况?在 C++ 或 Java 中,我会抛出异常以被调用者捕获。

4

5 回答 5

3

您始终可以使用返回值:

if( /* some bad parameters */ )
   return -1;

接着 :

int value = foo( something );
if( value == -1 )
   // error
else
   // no error

或传递另一个参数:

int foo( char s[], int* value )
{
    if( /* error */ )
        return 1;// error code 1
    // ...
    *value = something;
    return 0;
}

然后,当您调用该函数时,您可以验证它是否正确执行:

 if( foo( "something", &result ) )
 {
     //ok
 }
 else
 {
     // not ok
 }

这两种方法都意味着调用者将手动验证是否有错误

于 2015-08-19T13:55:23.310 回答
2

如果我希望该功能立即停止

两件事情。

  1. 如果您只想函数停止执行并返回给调用者,请使用return语句。此外,您可能希望使用一些预定义或用户定义的错误代码作为失败案例返回值,以区分失败原因和调用者。

  2. 如果您希望程序本身终止,请调用exit().

于 2015-08-19T13:54:09.183 回答
1

在任何 C 程序中进行错误处理的标准方法是为错误代码保留函数的返回值。

最典型的是,这是一个自定义枚举类型。例子:

typedef enum
{
  FOO_OK,
  FOO_ERR_STRLENGTH,
  FOO_ERR_DIVIDE_BY_ZERO,
  ...
} foo_err_t;


foo_err_t  foo_func (/* parameters */)
{
  if (strlen(s) < 1) 
  {
    return FOO_ERR_STRLENGTH;
  }

  ...

  return FOO_OK;
}

然后你正确地记录函数并说明它可能返回的错误代码,以及导致它们的原因。

发生错误时应该做什么通常与您的例程无关,而是应该由调用者决定。特别是,您的例程不应该决定终止整个程序。该决定应该由最外层的调用者(调用堆栈的顶部)做出,即来自 main()。

于 2015-08-19T14:03:07.623 回答
0

您的主要选择是:

  • 让返回值结合错误状态和实际值。例如,如果您的函数只打算返回非负值,那么您可以说负返回值表示错误。
  • 返回错误代码(0表示成功)并通过引用参数给出函数的输出。
  • 返回函数的输出并通过引用参数给出错误代码。

其他选项包括对错误状态使用全局(或线程局部)变量(恕我直言,这不是一个好主意),或者返回struct包含返回信息和错误状态的 a 。

于 2015-08-19T14:06:43.990 回答
0

如果我正确地考虑了您的问题,那么大多数类型错误都会在编译时被捕获。如果你想早点回来,你可以简单地打电话return。很多时候,错误处理,C程序员会goto为错误添加一个:

struct Data *
create_data ()
{
  struct Data *data = malloc(sizeof(struct Data));

  if (data == NULL)
      goto exit;

  /* do stuff with data */

exit:
    return data;
}

如果没有内存,那将返回 NULL。但是您可能出于另一个原因想提前退出。因此,如果您需要优雅地退出程序(并释放所有已占用的东西),您将需要一个中央退出点。

我通常有一个功能

void bail (const char *fmt, ...)
{
    va_list argp;
    va_start(argp, fmt);
      vfprintf(stderr, fmt, argp);
    va_end(argp);
    exit(EXIT_FAILURE);
}

它也打印STDERR并返回一个非 0 退出。您可以轻松修改它以接受您需要释放的任何数据。

于 2015-08-19T13:59:05.437 回答