7

我正在编写一个需要良好错误处理的 C 程序。代码是这样的:

If(doWork("A")<0){
    return -1;   
}
If(doWork("B")<0){
    undoWork("A");
    return -1;
}
If(doWork("C")<0){
    undoWork("A");
    undoWork("B");
    return -1;
}
return 0;

这段代码有效,但看起来很乱,特别是我有一长串doWork(X)要调用的。在这种情况下,是否有更好、更清洁的方法来处理错误?

4

6 回答 6

7

有些人,尤其是初学者到中级程序员,对在生产代码中看到有非常特殊的反应goto,但是顺序获取资源和错误时智能释放的惯用语如下:

if(doWork("A") < 0)
  goto errA;

if(doWork("B") < 0)
  goto errB;

if(doWork("C") < 0)
  goto errC;

/* success! */
return 0;

/* Error handling / releasing resources section */
errC:
  undoWork("B");
errB:
  undoWork("A");
errA:

return -1;

您将在系统代码中看到大量示例,例如在 linux 内核中。

于 2012-04-07T02:54:22.463 回答
2

作为同一个任务doWork,您可能可以定义一个链表或向量jobs并将其作为参数传递给doWork,将相应的信息附加到函数内部的此列表中,并且只调用undoWork一次:

If(doWork("A", &jobs)<0){
    return -1;   
}
If(doWork("B", &jobs)<0){
    undoWork(jobs);
    return -1;
}
If(doWork("C", &jobs)<0){
    undoWork(jobs);
    return -1;
}
return 0;

这样,无论要撤消的作业组合如何,您的逻辑都不会变得过于复杂。

与@twain249 的解决方案相比,优势在于该函数决定是否将作业添加到列表中,因此您有一个很好的隔离和模块化。

您当然可以将某种形式的可交互数据结构与此结合起来,以进一步减少重复代码的数量

for(i=0; i < jobdata.size; i++) {
    If(doWork(jobdata[i], &jobs)<0){
        undowork(jobs);
        return -1;   
    }
}

如您所见,数据结构设计在算法设计中起着重要作用,通常比人们通常认为的重要得多。

可能有数千个工作,代码将保持四行。

于 2012-04-07T02:41:58.247 回答
0

可能不是。像 C++ 和 C# 这样的新语言更喜欢异常来帮助改善这种情况。

也许您可以有一个表格,以某种方式指示您已完成哪些任务并撤消这些任务。但我真的认为这会使你的代码更复杂而不是更少。

另请注意,虽然使用 有一些非常强烈的感觉goto,但实际上有时可以简化这样的结构。

于 2012-04-07T02:31:29.073 回答
0

如果可以将您必须调用的所有内容存储doWork在一个数组中,那么您可以显着缩短代码,例如。

int i = 0;
int len = MAX_NUM; //set to the value of calls
int error = 0;

for(i = 0; i < len; i++) {
    if(doWork(a[i]) < 0) {
        error = 1;
        break;
    }
}

if(error) {
    for(int j = 0; j < i; i++) {
        undoWork(a[j]);
    }
    return -1;
}
于 2012-04-07T02:40:19.577 回答
0

如果你没有一个超长的列表,你可以这样处理。

if (dowork("A") >=0) {
if (dowork("B") >=0) {
if (dowork("C") >=0) {
if (dowork("D") >=0) return 0;
undowork("C"); }
undowork("B"); }
undowork("A"); }
return -1;
于 2012-04-07T03:26:06.637 回答
0

还有另一种广泛使用的方法,它基于清晰且不需要 goto 的单遍循环。这意味着尽管 Undo 函数可以正确处理已完成和未完成的工作。

do
{
  if(doWork("A")<0)
    break;   

  if(doWork("B")<0)
    break;

  if(doWork("C")<0)
    break;

  return 0;
}
while(0);

undoWork("A");
undoWork("B");
undoWork("C");
return -1;
于 2012-04-07T03:51:40.347 回答