C 处理函数错误消息的最理想方法?
假设我有一个函数来执行一个小而特殊的任务,这个任务很有可能失败。处理出问题的最好方法是什么?(假设我知道问题所在) 例如,假设我有一个函数,它读取一个双字节字符串并返回它:C 处理函数错误消息的最理想方法?,c,function,error-handling,return-value,stderr,C,Function,Error Handling,Return Value,Stderr,假设我有一个函数来执行一个小而特殊的任务,这个任务很有可能失败。处理出问题的最好方法是什么?(假设我知道问题所在) 例如,假设我有一个函数,它读取一个双字节字符串并返回它: #include <stdio.h> #include <stdlib.h> char *bar(void) { char *foo = malloc(3); scanf("%2s", foo); return foo; } int main(void) { cha
#include <stdio.h>
#include <stdlib.h>
char *bar(void)
{
char *foo = malloc(3);
scanf("%2s", foo);
return foo;
}
int main(void)
{
char *foo = bar();
puts(foo);
free(foo);
return 0;
}
如果我调用的函数是一个int
,这就不会有太大问题,因为这样我就可以根据出错的地方返回一个不同的整数值。但是在char*
的情况下,我通常尝试在失败时返回NULL
(因此FAILUREA
和FAILUREB
都将返回NULL
);没有办法知道是什么导致函数失败
因此,我的问题是,在处理错误消息时,什么是最佳做法?允许调用者处理错误报告更好,因为:
- 如果该功能构成库的一部分,则stderr可能不可用,并且需要替代报告机制
- 调用代码可能具有可采取的替代操作,并且可能不会将函数
的故障视为实际故障,无需报告bar()
enum Status
{
STATUS_OK,
STATUS_MEMORY_ALLOCATION_FAILURE,
STATUS_ACCESS_DENIED
};
enum Status status;
char* foo = bar(&status);
if (!foo)
{
if (STATUS_MEMORY_ALLOCATION_FAILURE == status)
{
/* report failure. */
}
else if (STATUS_ACCESS_DENIED == status)
{
/* try somewhere else */
}
}
如果函数返回超过1个错误案例,则可以使用这种方法
#include <stdio.h>
#include <stdlib.h>
int bar(char **foo)
{
if(!(malloc(3))) return 1; /* return error case 1*/
scanf("%2s", *foo);
if(!(malloc(4))) return 2; /* return error case 2*/
return 0; /* no error*/
}
int catcherror(int error)
{
switch (error) {
case 1:
/*do something 1*/
case 2:
/*do something 1*/
case 3:
/*do something 1*/
case 4:
/*do something 1*/
case 5:
/*do something 1*/
default:
/*do something 1*/
}
}
int main(void)
{
char *foo;
int error
error = bar(&foo);
catcherror(error);
puts(foo);
free(foo);
return 0;
}
#包括
#包括
整型条(字符**foo)
{
if(!(malloc(3)))返回1;/*返回错误案例1*/
scanf(“%2s”,*foo);
if(!(malloc(4)))返回2;/*返回错误案例2*/
返回0;/*无错误*/
}
int CATCH错误(int错误)
{
开关(错误){
案例1:
/*做点什么*/
案例2:
/*做点什么*/
案例3:
/*做点什么*/
案例4:
/*做点什么*/
案例5:
/*做点什么*/
违约:
/*做点什么*/
}
}
内部主(空)
{
char*foo;
整数错误
错误=条形图(&foo);
捕捉错误(错误);
看跌期权(foo);
免费(foo);
返回0;
}
如果您的项目包含许多返回常见错误案例的函数,那么
catcherror()
函数可能非常有用如果您可以对故障采取任何措施,并且如果您打算这样做,那么您可以这样做。
否则,您可以实现一个通用故障函数,在发生错误时调用该函数,并在一天内调用该函数:
void error(const char* format, ...)
{
va_list vl;
va_start(vl, format);
vfprintf(stderr, format, vl);
va_end(vl);
exit(-1);
}
您可以选择将其包装在宏中,并提供行#和文件名:
#define ERROR(fmt, ...) \
error("file:'%s',line:%d " fmt, __FILE__, __LINE__, __VA_ARGS__)
这将使控制台中的错误非常容易识别,因为错误消息准确地告诉文件和其中发生错误的行
典型用法,没什么特别之处:
char *bar(void)
{
char *foo;
if ((foo=malloc(3)) == NULL)
ERROR("malloc() failed!\n");
if (scanf("%2s", foo) != 1)
ERROR("scanf() failed!\n");
return foo;
}
您可以使用longjmp()
代替exit(-1)
立即返回调用者(=执行相应setjmp()
的调用者)。如果您想在出现错误时实际执行某些操作,可以关闭所有打开以写入的文件,这样缓冲数据就不会丢失
例如,如果您正在编写一个简单的编译器,这种error()
对于编译器内部的大多数错误和正在编译的源代码中的问题(例如,缺少冒号/paren或其他使代码无法编译的东西)来说已经足够了
如果您不能或不想执行这些操作,则需要仔细编写代码,进行适当的清理,并返回不同的错误代码,以便向调用者传达可操作的错误。
If(!(foo=malloc(3)))返回0代码>否,在bar()函数中,就在“Method2”malloc()下面。首先,您的malloc
不会在任何位置分配该内存。。。所以不管发生什么,这都是一个漏洞。。。但这里的错误处理相当主观。处理错误的位置由您决定(或者如果您在Linux内核中编程,他们喜欢让它崩溃以获得回溯!)我个人更喜欢在函数中处理它,在函数中错误会保持我的main()
干净,但是这真的取决于你。@wildplasser哦,是的,woops只是在飞行中写下了这一点,我现在就纠正它,谢谢你的输入,迈克,我很感激。太棒了,正是我想要的。也很简单,切中要害。谢谢你的回答!
void error(const char* format, ...)
{
va_list vl;
va_start(vl, format);
vfprintf(stderr, format, vl);
va_end(vl);
exit(-1);
}
#define ERROR(fmt, ...) \
error("file:'%s',line:%d " fmt, __FILE__, __LINE__, __VA_ARGS__)
char *bar(void)
{
char *foo;
if ((foo=malloc(3)) == NULL)
ERROR("malloc() failed!\n");
if (scanf("%2s", foo) != 1)
ERROR("scanf() failed!\n");
return foo;
}