Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从函数返回多个错误之一并用C语言结束程序的最佳实践是什么?_C - Fatal编程技术网

从函数返回多个错误之一并用C语言结束程序的最佳实践是什么?

从函数返回多个错误之一并用C语言结束程序的最佳实践是什么?,c,C,我找不到从函数中的函数返回错误并结束程序的方法 我曾考虑使用一个结构并将返回值存储在其中,然后以这种方式结束它,但我不知道这是否是最佳实践 假设我有这样一个程序: int main() { // do stuff importantFunction(); // do stuff return 0; } 在importantFunction中,我调用了另外两个函数,它们正在进行一些位移位,并且总是返回一个数组。现在我想尝试返回1或0x01,因为如果此函数中的一个函数发生错误,该

我找不到从函数中的函数返回错误并结束程序的方法

我曾考虑使用一个结构并将返回值存储在其中,然后以这种方式结束它,但我不知道这是否是最佳实践

假设我有这样一个程序:

int main()
{
  // do stuff 
  importantFunction();
  // do stuff
  return 0;
}
在importantFunction中,我调用了另外两个函数,它们正在进行一些位移位,并且总是返回一个数组。现在我想尝试返回1或0x01,因为如果此函数中的一个函数发生错误,该函数将返回数组指针,但我不确定如何返回

char *importantFunction()
{
  //do stuff
  secoundFunction();
  thirdFunction();
  //do stuff
  return array;
 }


char *secoundFunction()
{
  // do stuff
  if (something == x)
    return array;
  // do stuff
  return array;
}
我只是想找到一个方法,而不必检查第一个函数是否等于某个值,然后在int main中结束程序。 我试图避免这种情况,因为它并不总是起作用:

int main()
{
  // do stuff 
  char *pointer = importantFunction();
  if (*pointer == 'something')
    return 1;
  if (*pointer == 'something')
    return 2;
  if (*pointer == 'something')
    return 3;
  // and so on...
  // do stuff
  return 0;
}

如果这是一个愚蠢的问题,我很抱歉,我不太擅长提问。

C中处理错误的一种常见方法是通过返回值

假设函数f成功返回指向字符串的指针

char *f();
此类函数在出现故障时将返回空指针,您可以通过包含一些常见头文件(例如)来获得空指针

现在假设g是一个函数,它给定一个整数,计算一些东西并返回运算的整数结果,但该函数可能会失败,例如,参数对计算无效,谁知道呢。。。。那也许你想这样写

int g(int i, int *result);
这里,i是用于计算某些内容的参数,result是指向将用于存储结果的变量的指针。为什么g的返回类型是int?好吧,它可以是bool,但通常是一个使用int。。。返回值将用作布尔值,g在失败时返回0,成功时返回1

可以在第三个函数h中这样使用这些函数


C中处理错误的一种常见方法是通过返回值

假设函数f成功返回指向字符串的指针

char *f();
此类函数在出现故障时将返回空指针,您可以通过包含一些常见头文件(例如)来获得空指针

现在假设g是一个函数,它给定一个整数,计算一些东西并返回运算的整数结果,但该函数可能会失败,例如,参数对计算无效,谁知道呢。。。。那也许你想这样写

int g(int i, int *result);
这里,i是用于计算某些内容的参数,result是指向将用于存储结果的变量的指针。为什么g的返回类型是int?好吧,它可以是bool,但通常是一个使用int。。。返回值将用作布尔值,g在失败时返回0,成功时返回1

可以在第三个函数h中这样使用这些函数


不要使用指针返回带外错误代码。指针无效时为NULL或有效,通常在程序中堆栈溢出。正在执行char*pointer=char*uintpttr_t1;这只是让人困惑,如果uintptr_tpointer==1{..}那么做同样是不可维护的

返回一个int。int在C标准库中通常用于返回错误。通常C库在出错时返回-1,设置errno-I通常编写返回负值的库代码,即在malloc失败时返回-ENOMEM。成功时返回0,可能返回正值以通知库中某些状态的用户代码。通过指针传递要设置的所有变量。看例句意见:不要使用fopen_s,只看它

enum importantFunction_rets_e {
   IMPORTANT_FUNCTION_ERR_1 = -1,
   IMPORTANT_FUNCTION_ERR_2 = -2,
   IMPORTANT_FUNCTION_STATE_1 = 1,
   IMPORTANT_FUNCTION_STATE_2 = 2,
};

int importantFunction(char **pointer)
{
   assert(pointer != NULL);
   // or maybe
   if (pointer == NULL) return -EINVAL;

   int ret;
   ret = secondFunction(pointer);
   if (ret < 0) return ret;
   ret = thirdFunction(pointer);
   if (ret < 0) return ret; 
   return 0;
}

int secondFunction(char **pointer) {
  *pointer = malloc(sizeof(char) * 5);
   if (*pointer == NULL) {
      return IMPORTANT_FUNCTION_ERR_1;
   }
   memcpy(*pointer, "hey!", 5);
   return 0;
}

int main() {
    char *pointer;
    const int importantFunction_ret = importantFunction(&pointer);
    if (importantFunction_ret < 0) {
       if (importantFunction_ret == IMPORTANT_FUNCTION_ERR_1) {
          // handle err 1
       } else if (importantFunction_ret == IMPORTANT_FUNCTION_ERR_2) {
          // handle err 2
       } else {
          // hanlde other errors
       }
       return -1;
    }
    if (importantFunction_ret == IMPORTANT_FUNCTION_STATE_1) { 
         // handle state1
    } else if {importantFunction_ret == IMPORTANT_FUNCTION_STATE_2) {
        // handle state2
    } else {
        // handle other states 
        assert(0);
    }
}

如果您想探索C语言中的主题或错误处理,您可以实现新的还是旧的?使用与面向对象语言相同的方法使用std::variant或std::expected或类似的观点:我确实反对这个建议,因为它现在是这样,它需要重新设计/重构,但这将是C向前迈出的一大步。

不要用指针返回带外错误代码。指针无效时为NULL或有效,通常在程序中堆栈溢出。正在执行char*pointer=char*uintpttr_t1;这只是让人困惑,如果uintptr_tpointer==1{..}那么做同样是不可维护的

返回一个int。int在C标准库中通常用于返回错误。通常C库在出错时返回-1,设置errno-I通常编写返回负值的库代码,即在malloc失败时返回-ENOMEM。成功时返回0,可能返回正值以通知库中某些状态的用户代码。通过指针传递要设置的所有变量。看例句意见:不要使用fopen_s,只看它

enum importantFunction_rets_e {
   IMPORTANT_FUNCTION_ERR_1 = -1,
   IMPORTANT_FUNCTION_ERR_2 = -2,
   IMPORTANT_FUNCTION_STATE_1 = 1,
   IMPORTANT_FUNCTION_STATE_2 = 2,
};

int importantFunction(char **pointer)
{
   assert(pointer != NULL);
   // or maybe
   if (pointer == NULL) return -EINVAL;

   int ret;
   ret = secondFunction(pointer);
   if (ret < 0) return ret;
   ret = thirdFunction(pointer);
   if (ret < 0) return ret; 
   return 0;
}

int secondFunction(char **pointer) {
  *pointer = malloc(sizeof(char) * 5);
   if (*pointer == NULL) {
      return IMPORTANT_FUNCTION_ERR_1;
   }
   memcpy(*pointer, "hey!", 5);
   return 0;
}

int main() {
    char *pointer;
    const int importantFunction_ret = importantFunction(&pointer);
    if (importantFunction_ret < 0) {
       if (importantFunction_ret == IMPORTANT_FUNCTION_ERR_1) {
          // handle err 1
       } else if (importantFunction_ret == IMPORTANT_FUNCTION_ERR_2) {
          // handle err 2
       } else {
          // hanlde other errors
       }
       return -1;
    }
    if (importantFunction_ret == IMPORTANT_FUNCTION_STATE_1) { 
         // handle state1
    } else if {importantFunction_ret == IMPORTANT_FUNCTION_STATE_2) {
        // handle state2
    } else {
        // handle other states 
        assert(0);
    }
}
如果您想探索C语言中的主题或错误处理,您可以实现新的还是旧的?使用与面向对象语言相同的方法使用std::variant或std::expected或类似的观点:我真的反对这个提议,因为它现在是这样,它需要重新设计/重构,但这将是一大步
对于C.

有三种从函数返回错误的常见模式:

让函数返回一个int,具体值表示成功和失败

例如,从main返回EXIT_SUCCESS或EXIT_FAILURE是C标准建议报告整个流程成功或失败的方式。BSD变体试图标准化一些其他代码;如果您的系统有一个标题,您可以使用这些标题。但请注意,它们并不是标准的,只是我们最接近达成协议的一件事,即流程如何报告错误代码

为错误保留特定的返回值,并使用全局或线程局部变量(通常为errno)来描述错误

大多数标准C库函数都这样做,函数返回int时使用-1表示错误,函数返回指针时使用NULL表示错误

使用额外参数指向错误指示器

这种方法在从Fortran派生的代码和接口中很常见。通常,错误指示符是可选的,如果调用方对结果是否有效不感兴趣,则可能会将其保留为空

我自己的规则很简单:

在编写低级库时,首选第二种方法。对于熟悉标准C库的人来说,这是一种熟悉的方法

对可恢复的错误使用第一种方法

通常,我使用return 0将它与第二个结合起来;追求成功,回报错误;或返回errno=EINVAL;等等,以防出错。最后一个首先将EINVAL分配给errno,然后返回EINVAL

当错误状态应该在许多操作中保留,或者存在状态错误影响的结构时,请使用第三种方法

让我们看看这些方法在实践中有何不同

一件非常常见的事情是将命令行参数解析为数字。让我们看一个例子,在某种计算中,参数将用作双精度:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    int     arg;
    double  val;    

    for (arg = 1; arg < argc; arg++) {
        if (sscanf(argv[arg], "%lf", &val) == 1) {
            printf("argv[%d] = %.6f\n", arg, val);
        } else {
            printf("%s: Not a number.\n", argv[arg]);
            exit(EXIT_FAILURE);
        }
    }

    return EXIT_SUCCESS;
}
这是可行的,因为sscanf返回成功转换的次数,我们只希望双转换%lf工作,而字符转换%c失败

不幸的是,scanf系列函数不检查溢出。如果你提供的数字足够大,它就会被悄悄地破坏。不好的。为了避免这种情况,我们可以使用strtod。为了简化使用,我们可以将它放在单独的函数parse_double中。但是,该如何返回值以及可能的错误?要执行以下哪一项

/* Convert the initial double, returning the pointer to the rest of the
   string; or NULL if an error occurs. */
const char *parse_double(const char *src, double *to);

/* If the string contains exactly one double, convert it and return 0.
   Otherwise return a nonzero error code. */
int parse_double(const char *src, double *to);

/* Convert the string to a double as best as you can. If an error occurs, return 'errval'. */
double parse_double(const char *src, const double errval);
那么,哪一个是最好的呢

答案当然是,这取决于用例

实际上,我已经在不同的程序中实现了这三个,这取决于哪一个是最合适的

当使用相同的函数来解析输入文件时,第一个函数特别有用,并且/或者我们允许每个参数/行有任意数量的双精度。它很容易在循环中使用

第二个是我在程序中最常用的。我经常使用

typedef struct {
    double  x;
    double  y;
    double  z;
} vec3d;

int parse_vector(const char *src, vec3d *to)
{
    vec3d  temp;
    char   dummy;

    if (!src || !*src)
        return -1; /* NULL or empty string */

    if (sscanf(src, " %lf %lf %lf %c", &temp.x, &temp.y, &temp.z, &dummy) == 3 ||
        sscanf(src, " %lf %*[.,:/] %lf %*[.,:/] %lf %c", &temp.x, &temp.y, &temp.z, &dummy) == 3) {
        if (to)
            *to = temp;
        return 0;
    }

    return -1;
}
它允许在命令行上使用1+2+3、1/2/3、1:2:3甚至“1 2 3”或1 2 3指定3D向量。需要引号来阻止shell将其拆分为三个单独的参数。它不会检查双重溢出,因此在输出中显示已解析的向量非常重要,这样用户就可以检测到他们的输入是否有误


%*[,:/]中的星号*表示转换结果不存储在任何位置,并且转换不计入返回值。[是转换说明符,转换列表中的任何和所有字符,以]字符结尾。[^是相反的,转换列表中未包含的所有字符。

函数返回错误有三种常见模式:

让函数返回一个int,具体值表示成功和失败

例如,从main返回EXIT_SUCCESS或EXIT_FAILURE是C标准建议报告整个流程成功或失败的方式。BSD变体试图标准化一些其他代码;如果您的系统有标头,则可以使用这些代码。但请注意,它们不是标准的,只是我们必须达成一致的最接近的一种方式说明进程如何报告错误代码

为错误保留特定的返回值,并使用全局或线程局部变量(通常为errno)来描述错误

大多数标准C库函数都这样做,函数返回int时使用-1表示错误,函数返回指针时使用NULL表示错误

使用额外参数指向错误指示器

这种方法在从Fortran派生的代码和接口中很常见。通常,错误指示符是可选的,如果调用方对结果是否有效不感兴趣,则可以将其保留为空

我自己的规则很简单:

在编写低级库时,首选第二种方法。这是熟悉标准C库的人所熟悉的方法

U se是可恢复错误的第一种方法

通常,我使用return 0将它与第二个结合起来;追求成功,回报错误;或返回errno=EINVAL;等等,以防出错。最后一个首先将EINVAL分配给errno,然后返回EINVAL

当错误状态应该在许多操作中保留,或者存在状态错误影响的结构时,请使用第三种方法

让我们看看这些方法在实践中有何不同

一件非常常见的事情是将命令行参数解析为数字。让我们看一个例子,在某种计算中,参数将用作双精度:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    int     arg;
    double  val;    

    for (arg = 1; arg < argc; arg++) {
        if (sscanf(argv[arg], "%lf", &val) == 1) {
            printf("argv[%d] = %.6f\n", arg, val);
        } else {
            printf("%s: Not a number.\n", argv[arg]);
            exit(EXIT_FAILURE);
        }
    }

    return EXIT_SUCCESS;
}
这是可行的,因为sscanf返回成功转换的次数,我们只希望双转换%lf工作,而字符转换%c失败

不幸的是,scanf系列函数不检查溢出。如果你提供的数字足够大,它就会被悄悄地破坏。不好的。为了避免这种情况,我们可以使用strtod。为了简化使用,我们可以将它放在单独的函数parse_double中。但是,该如何返回值以及可能的错误?要执行以下哪一项

/* Convert the initial double, returning the pointer to the rest of the
   string; or NULL if an error occurs. */
const char *parse_double(const char *src, double *to);

/* If the string contains exactly one double, convert it and return 0.
   Otherwise return a nonzero error code. */
int parse_double(const char *src, double *to);

/* Convert the string to a double as best as you can. If an error occurs, return 'errval'. */
double parse_double(const char *src, const double errval);
那么,哪一个是最好的呢

答案当然是,这取决于用例

实际上,我已经在不同的程序中实现了这三个,这取决于哪一个是最合适的

当使用相同的函数来解析输入文件时,第一个函数特别有用,并且/或者我们允许每个参数/行有任意数量的双精度。它很容易在循环中使用

第二个是我在程序中最常用的。我经常使用

typedef struct {
    double  x;
    double  y;
    double  z;
} vec3d;

int parse_vector(const char *src, vec3d *to)
{
    vec3d  temp;
    char   dummy;

    if (!src || !*src)
        return -1; /* NULL or empty string */

    if (sscanf(src, " %lf %lf %lf %c", &temp.x, &temp.y, &temp.z, &dummy) == 3 ||
        sscanf(src, " %lf %*[.,:/] %lf %*[.,:/] %lf %c", &temp.x, &temp.y, &temp.z, &dummy) == 3) {
        if (to)
            *to = temp;
        return 0;
    }

    return -1;
}
它允许在命令行上使用1+2+3、1/2/3、1:2:3甚至“1 2 3”或1 2 3指定3D向量。需要引号来阻止shell将其拆分为三个单独的参数。它不会检查双重溢出,因此在输出中显示已解析的向量非常重要,这样用户就可以检测到他们的输入是否有误


%*[,:/]中的星号*表示转换结果不存储在任何位置,并且转换不计入返回值。[是转换说明符,转换列表中的任何和所有字符,以]字符结尾。[^是相反的,转换列表中不包含的任何字符。

我意识到的一件事是,在堆栈中过滤致命错误通常是不值得的。如果某个错误导致无法向前推进,只需在那里结束程序。我通常通过创建一个可以执行的错误退出函数来处理它从任何地方拨打:

void error_exit(int code, const char* message) {
  printf("Error %d: %s\nExiting!\n", code, message);
  cleanup();
  exit(code);
}

float* nested_function(int input, ...) {
  if (causes_hopeless_failure(input)) {
    error_exit(err_HOPELESS, "invalid input to nested_function");
  }
  //normal processing proceeds ...
  return valid_pointer;
}

int main() {
   float* vector = function_which_eventually_calls_nested_function();
   cleanup();
   return 0;
}

cleanup函数用于处理程序退出时未正确清理的资源。文件句柄和分配的缓冲区通常不属于这一类。我通常将其用于需要撤消的系统配置更改。

我意识到,通常不值得费心过滤堆栈上的错误。如果某个错误导致无法向前推进,只需在那里结束程序。我通常通过创建一个可以从任何地方调用的error_exit函数来处理它:

void error_exit(int code, const char* message) {
  printf("Error %d: %s\nExiting!\n", code, message);
  cleanup();
  exit(code);
}

float* nested_function(int input, ...) {
  if (causes_hopeless_failure(input)) {
    error_exit(err_HOPELESS, "invalid input to nested_function");
  }
  //normal processing proceeds ...
  return valid_pointer;
}

int main() {
   float* vector = function_which_eventually_calls_nested_function();
   cleanup();
   return 0;
}

清理功能用于处理在程序退出时未正确清理的资源。文件句柄和分配的缓冲区通常不属于这一类。我通常将其用于需要撤消的系统配置更改。

C有带外错误代码处理,它从永远都在其中

#include <errno.h>

int do_something(char* data) {
   if ( data == 0 ) {
      errno = ENODATA;
      return 0;
   }
   ... do stuff ...
}
如果希望链错误

int value = do_something( "one" );
if ( int errornum = errno ) {
   fprintf("error (%d) could not do something: %s", strerror( errornum ) );
   errno = errornum;
   return; // or exit;
} 
请记住,几乎每一个标准函数调用都会重置errno,因此您需要捕获它,然后在执行任何您想要的操作后可以选择再次设置它

errno的使用通常没有达到应有的程度,这可能是因为太多人首先通过特殊的哨兵/值来学习带内错误报告。此外,正确检查错误代码需要更多的代码行。也就是说,这是一个更好的解决方案,因为您不会让返回值过载数据和co同一变量中的控件信息

已经设置了许多错误代码,奇怪的是,您可以根据需要重用一个,或者选择一个足够接近的错误代码

1  EPERM Operation not permitted
2   ENOENT  No such file or directory
3   ESRCH   No such process
4   EINTR   Interrupted system call
5   EIO     I/O error
6   ENXIO   No such device or address
7   E2BIG   Argument list too long
8   ENOEXEC     Exec format error
9   EBADF   Bad file number
10  ECHILD  No child processes
11  EAGAIN  Try again
12  ENOMEM  Out of memory
13  EACCES  Permission denied
14  EFAULT  Bad address
15  ENOTBLK     Block device required
16  EBUSY   Device or resource busy
17  EEXIST  File exists
18  EXDEV   Cross-device link
19  ENODEV  No such device
20  ENOTDIR     Not a directory
21  EISDIR  Is a directory
22  EINVAL  Invalid argument
23  ENFILE  File table overflow
24  EMFILE  Too many open files
25  ENOTTY  Not a typewriter
26  ETXTBSY     Text file busy
27  EFBIG   File too large
28  ENOSPC  No space left on device
29  ESPIPE  Illegal seek
30  EROFS   Read-only file system
31  EMLINK  Too many links
32  EPIPE   Broken pipe
33  EDOM    Math argument out of domain of func
34  ERANGE  Math result not representable
35  EDEADLK     Resource deadlock would occur
36  ENAMETOOLONG    File name too long
37  ENOLCK  No record locks available
38  ENOSYS  Function not implemented
39  ENOTEMPTY   Directory not empty
40  ELOOP   Too many symbolic links encountered
42  ENOMSG  No message of desired type
43  EIDRM   Identifier removed
44  ECHRNG  Channel number out of range
45  EL2NSYNC    Level 2 not synchronized
46  EL3HLT  Level 3 halted
47  EL3RST  Level 3 reset
48  ELNRNG  Link number out of range
49  EUNATCH     Protocol driver not attached
50  ENOCSI  No CSI structure available
51  EL2HLT  Level 2 halted
52  EBADE   Invalid exchange
53  EBADR   Invalid request descriptor
54  EXFULL  Exchange full
55  ENOANO  No anode
56  EBADRQC     Invalid request code
57  EBADSLT     Invalid slot
59  EBFONT  Bad font file format
60  ENOSTR  Device not a stream
61  ENODATA     No data available
62  ETIME   Timer expired
63  ENOSR   Out of streams resources
64  ENONET  Machine is not on the network
65  ENOPKG  Package not installed
66  EREMOTE     Object is remote
67  ENOLINK     Link has been severed
68  EADV    Advertise error
69  ESRMNT  Srmount error
70  ECOMM   Communication error on send
71  EPROTO  Protocol error
72  EMULTIHOP   Multihop attempted
73  EDOTDOT     RFS specific error
74  EBADMSG     Not a data message
75  EOVERFLOW   Value too large for defined data type
76  ENOTUNIQ    Name not unique on network
77  EBADFD  File descriptor in bad state
78  EREMCHG     Remote address changed
79  ELIBACC     Can not access a needed shared library
80  ELIBBAD     Accessing a corrupted shared library
81  ELIBSCN     .lib section in a.out corrupted
82  ELIBMAX     Attempting to link in too many shared libraries
83  ELIBEXEC    Cannot exec a shared library directly
84  EILSEQ  Illegal byte sequence
85  ERESTART    Interrupted system call should be restarted
86  ESTRPIPE    Streams pipe error
87  EUSERS  Too many users
88  ENOTSOCK    Socket operation on non-socket
89  EDESTADDRREQ    Destination address required
90  EMSGSIZE    Message too long
91  EPROTOTYPE  Protocol wrong type for socket
92  ENOPROTOOPT     Protocol not available
93  EPROTONOSUPPORT     Protocol not supported
94  ESOCKTNOSUPPORT     Socket type not supported
95  EOPNOTSUPP  Operation not supported on transport endpoint
96  EPFNOSUPPORT    Protocol family not supported
97  EAFNOSUPPORT    Address family not supported by protocol
98  EADDRINUSE  Address already in use
99  EADDRNOTAVAIL   Cannot assign requested address
100     ENETDOWN    Network is down
101     ENETUNREACH     Network is unreachable
102     ENETRESET   Network dropped connection because of reset
103     ECONNABORTED    Software caused connection abort
104     ECONNRESET  Connection reset by peer
105     ENOBUFS     No buffer space available
106     EISCONN     Transport endpoint is already connected
107     ENOTCONN    Transport endpoint is not connected
108     ESHUTDOWN   Cannot send after transport endpoint shutdown
109     ETOOMANYREFS    Too many references: cannot splice
110     ETIMEDOUT   Connection timed out
111     ECONNREFUSED    Connection refused
112     EHOSTDOWN   Host is down
113     EHOSTUNREACH    No route to host
114     EALREADY    Operation already in progress
115     EINPROGRESS     Operation now in progress
116     ESTALE  Stale NFS file handle
117     EUCLEAN     Structure needs cleaning
118     ENOTNAM     Not a XENIX named type file
119     ENAVAIL     No XENIX semaphores available
120     EISNAM  Is a named type file
121     EREMOTEIO   Remote I/O error
122     EDQUOT  Quota exceeded
123     ENOMEDIUM   No medium found
124     EMEDIUMTYPE     Wrong medium type
125     ECANCELED   Operation Canceled
126     ENOKEY  Required key not available
127     EKEYEXPIRED     Key has expired
128     EKEYREVOKED     Key has been revoked
129     EKEYREJECTED    Key was rejected by service
130     EOWNERDEAD  Owner died
131     ENOTRECOVERABLE     State not recoverable

C有带外错误代码处理,从永远都在那里

#include <errno.h>

int do_something(char* data) {
   if ( data == 0 ) {
      errno = ENODATA;
      return 0;
   }
   ... do stuff ...
}
如果希望链错误

int value = do_something( "one" );
if ( int errornum = errno ) {
   fprintf("error (%d) could not do something: %s", strerror( errornum ) );
   errno = errornum;
   return; // or exit;
} 
请记住,几乎每一个标准函数调用都会重置errno,因此您需要捕获它,然后在执行任何您想要的操作后可以选择再次设置它

errno的使用通常没有达到应有的程度,这可能是因为太多人首先通过特殊的哨兵/值来学习带内错误报告。此外,正确检查错误代码需要更多的代码行。也就是说,这是一个更好的解决方案,因为您不会让返回值过载数据和co同一变量中的控件信息

已经设置了许多错误代码 奇怪的是,你可以根据自己的需要重复使用一个,或者选择一个足够近的

1  EPERM Operation not permitted
2   ENOENT  No such file or directory
3   ESRCH   No such process
4   EINTR   Interrupted system call
5   EIO     I/O error
6   ENXIO   No such device or address
7   E2BIG   Argument list too long
8   ENOEXEC     Exec format error
9   EBADF   Bad file number
10  ECHILD  No child processes
11  EAGAIN  Try again
12  ENOMEM  Out of memory
13  EACCES  Permission denied
14  EFAULT  Bad address
15  ENOTBLK     Block device required
16  EBUSY   Device or resource busy
17  EEXIST  File exists
18  EXDEV   Cross-device link
19  ENODEV  No such device
20  ENOTDIR     Not a directory
21  EISDIR  Is a directory
22  EINVAL  Invalid argument
23  ENFILE  File table overflow
24  EMFILE  Too many open files
25  ENOTTY  Not a typewriter
26  ETXTBSY     Text file busy
27  EFBIG   File too large
28  ENOSPC  No space left on device
29  ESPIPE  Illegal seek
30  EROFS   Read-only file system
31  EMLINK  Too many links
32  EPIPE   Broken pipe
33  EDOM    Math argument out of domain of func
34  ERANGE  Math result not representable
35  EDEADLK     Resource deadlock would occur
36  ENAMETOOLONG    File name too long
37  ENOLCK  No record locks available
38  ENOSYS  Function not implemented
39  ENOTEMPTY   Directory not empty
40  ELOOP   Too many symbolic links encountered
42  ENOMSG  No message of desired type
43  EIDRM   Identifier removed
44  ECHRNG  Channel number out of range
45  EL2NSYNC    Level 2 not synchronized
46  EL3HLT  Level 3 halted
47  EL3RST  Level 3 reset
48  ELNRNG  Link number out of range
49  EUNATCH     Protocol driver not attached
50  ENOCSI  No CSI structure available
51  EL2HLT  Level 2 halted
52  EBADE   Invalid exchange
53  EBADR   Invalid request descriptor
54  EXFULL  Exchange full
55  ENOANO  No anode
56  EBADRQC     Invalid request code
57  EBADSLT     Invalid slot
59  EBFONT  Bad font file format
60  ENOSTR  Device not a stream
61  ENODATA     No data available
62  ETIME   Timer expired
63  ENOSR   Out of streams resources
64  ENONET  Machine is not on the network
65  ENOPKG  Package not installed
66  EREMOTE     Object is remote
67  ENOLINK     Link has been severed
68  EADV    Advertise error
69  ESRMNT  Srmount error
70  ECOMM   Communication error on send
71  EPROTO  Protocol error
72  EMULTIHOP   Multihop attempted
73  EDOTDOT     RFS specific error
74  EBADMSG     Not a data message
75  EOVERFLOW   Value too large for defined data type
76  ENOTUNIQ    Name not unique on network
77  EBADFD  File descriptor in bad state
78  EREMCHG     Remote address changed
79  ELIBACC     Can not access a needed shared library
80  ELIBBAD     Accessing a corrupted shared library
81  ELIBSCN     .lib section in a.out corrupted
82  ELIBMAX     Attempting to link in too many shared libraries
83  ELIBEXEC    Cannot exec a shared library directly
84  EILSEQ  Illegal byte sequence
85  ERESTART    Interrupted system call should be restarted
86  ESTRPIPE    Streams pipe error
87  EUSERS  Too many users
88  ENOTSOCK    Socket operation on non-socket
89  EDESTADDRREQ    Destination address required
90  EMSGSIZE    Message too long
91  EPROTOTYPE  Protocol wrong type for socket
92  ENOPROTOOPT     Protocol not available
93  EPROTONOSUPPORT     Protocol not supported
94  ESOCKTNOSUPPORT     Socket type not supported
95  EOPNOTSUPP  Operation not supported on transport endpoint
96  EPFNOSUPPORT    Protocol family not supported
97  EAFNOSUPPORT    Address family not supported by protocol
98  EADDRINUSE  Address already in use
99  EADDRNOTAVAIL   Cannot assign requested address
100     ENETDOWN    Network is down
101     ENETUNREACH     Network is unreachable
102     ENETRESET   Network dropped connection because of reset
103     ECONNABORTED    Software caused connection abort
104     ECONNRESET  Connection reset by peer
105     ENOBUFS     No buffer space available
106     EISCONN     Transport endpoint is already connected
107     ENOTCONN    Transport endpoint is not connected
108     ESHUTDOWN   Cannot send after transport endpoint shutdown
109     ETOOMANYREFS    Too many references: cannot splice
110     ETIMEDOUT   Connection timed out
111     ECONNREFUSED    Connection refused
112     EHOSTDOWN   Host is down
113     EHOSTUNREACH    No route to host
114     EALREADY    Operation already in progress
115     EINPROGRESS     Operation now in progress
116     ESTALE  Stale NFS file handle
117     EUCLEAN     Structure needs cleaning
118     ENOTNAM     Not a XENIX named type file
119     ENAVAIL     No XENIX semaphores available
120     EISNAM  Is a named type file
121     EREMOTEIO   Remote I/O error
122     EDQUOT  Quota exceeded
123     ENOMEDIUM   No medium found
124     EMEDIUMTYPE     Wrong medium type
125     ECANCELED   Operation Canceled
126     ENOKEY  Required key not available
127     EKEYEXPIRED     Key has expired
128     EKEYREVOKED     Key has been revoked
129     EKEYREJECTED    Key was rejected by service
130     EOWNERDEAD  Owner died
131     ENOTRECOVERABLE     State not recoverable

请添加实际代码,以便我们有一个清晰的示例,如果*pointer=='something'很像没有做您期望的事情;您可能需要ifpointer&&strcppointer,something==0太多了,如果可能的话,我只是想知道如何返回错误。函数必须作为字符指针返回。您知道退出,对吗?如果发生不可恢复的错误,例如,当前数据集的动态内存分配失败,只需打印一条错误消息,然后立即退出程序,这是完全可以接受的。@NominalAnimal我是,但我尽量不使用它。请添加实际的代码,让我们有一个明确的例子,如果*pointer=='something'很像没有做你期望的事情;您可能需要ifpointer&&strcppointer,something==0太多了,如果可能的话,我只是想知道如何返回错误。函数必须作为字符指针返回。您知道退出,对吗?如果发生不可恢复的错误,例如,当前数据集的动态内存分配失败,只打印一条错误消息,然后立即退出程序是完全可以接受的。@NominalAnimal我是,但我尝试不使用它。请注意,上面的列表并不详尽。请注意,上面的列表并不详尽。