有人可能会说一些关于异常的事情......但是在C中,有什么其他方法可以干净利落地清楚地完成以下操作并且不需要重复这么多代码?
if (Do1()) { printf("Failed 1"); return 1; }
if (Do2()) { Undo1(); printf("Failed 2"); return 2; }
if (Do3()) { Undo2(); Undo1(); printf("Failed 3"); return 3; }
if (Do4()) { Undo3(); Undo2(); Undo1(); printf("Failed 4"); return 4; }
if (Do5()) { Undo4(); Undo3(); Undo2(); Undo1(); printf("Failed 5"); return 5; }
Etc...
Run Code Online (Sandbox Code Playgroud)
这可能是使用gotos的一种情况.或者可能是多个内部功能......
lik*_*kle 47
是的,在这种情况下使用goto是很常见的,以避免重复自己.
一个例子:
int hello() {
int result;
if (Do1()) { result = 1; goto err_one; }
if (Do2()) { result = 2; goto err_two; }
if (Do3()) { result = 3; goto err_three; }
if (Do4()) { result = 4; goto err_four; }
if (Do5()) { result = 5; goto err_five; }
// Assuming you'd like to return 0 on success.
return 0;
err_five:
Undo4();
err_four:
Undo3();
err_three:
Undo2();
err_two:
Undo1();
err_one:
printf("Failed %i", result);
return result;
}
Run Code Online (Sandbox Code Playgroud)
与往常一样,您可能还希望保持较小的功能并以有意义的方式将操作批量组合在一起,以避免出现大的"撤消代码".
Bla*_*aze 18
这可能是使用gotos的一种情况.
当然,我们试试吧.这是一个可能的实现:
#include "stdio.h"
int main(int argc, char **argv) {
int errorCode = 0;
if (Do1()) { errorCode = 1; goto undo_0; }
if (Do2()) { errorCode = 2; goto undo_1; }
if (Do3()) { errorCode = 3; goto undo_2; }
if (Do4()) { errorCode = 4; goto undo_3; }
if (Do5()) { errorCode = 5; goto undo_4; }
undo_5: Undo5(); /* deliberate fallthrough */
undo_4: Undo4();
undo_3: Undo3();
undo_2: Undo2();
undo_1: Undo1();
undo_0: /* nothing to undo in this case */
if (errorCode != 0) {
printf("Failed %d\n", errorCode);
}
return errorCode;
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*m's 14
如果您的功能具有相同的签名,您可以执行以下操作:
bool Do1(void) { printf("function %s\n", __func__); return true;}
bool Do2(void) { printf("function %s\n", __func__); return true;}
bool Do3(void) { printf("function %s\n", __func__); return false;}
bool Do4(void) { printf("function %s\n", __func__); return true;}
bool Do5(void) { printf("function %s\n", __func__); return true;}
void Undo1(void) { printf("function %s\n", __func__);}
void Undo2(void) { printf("function %s\n", __func__);}
void Undo3(void) { printf("function %s\n", __func__);}
void Undo4(void) { printf("function %s\n", __func__);}
void Undo5(void) { printf("function %s\n", __func__);}
typedef struct action {
bool (*Do)(void);
void (*Undo)(void);
} action_s;
int main(void)
{
action_s actions[] = {{Do1, Undo1},
{Do2, Undo2},
{Do3, Undo3},
{Do4, Undo4},
{Do5, Undo5},
{NULL, NULL}};
for (size_t i = 0; actions[i].Do; ++i) {
if (!actions[i].Do()) {
printf("Failed %zu.\n", i + 1);
for (int j = i - 1; j >= 0; --j) {
actions[j].Undo();
}
return (i);
}
}
return (0);
}
Run Code Online (Sandbox Code Playgroud)
您可以更改其中一个Do函数的返回值以查看它的反应:)
为了完整性,有点混淆:
int foo(void)
{
int rc;
if (0
|| (rc = 1, do1())
|| (rc = 2, do2())
|| (rc = 3, do3())
|| (rc = 4, do4())
|| (rc = 5, do5())
|| (rc = 0)
)
{
/* More or less stolen from Chris' answer:
https://stackoverflow.com/a/53444967/694576) */
switch(rc - 1)
{
case 5: /* Not needed for this example, but left in in case we'd add do6() ... */
undo5();
case 4:
undo4();
case 3:
undo3();
case 2:
undo2();
case 1:
undo1();
default:
break;
}
}
return rc;
}
Run Code Online (Sandbox Code Playgroud)
使用gotoC语言来管理清理
例如,检查Linux 内核编码风格:
使用
gotos的理由是:
- 无条件语句更容易理解,并且减少了嵌套
- 防止在进行修改时不更新各个出口点而导致的错误
- 节省编译器的工作以优化冗余代码;)
例子:
Run Code Online (Sandbox Code Playgroud)int fun(int a) { int result = 0; char *buffer; buffer = kmalloc(SIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; if (condition1) { while (loop1) { ... } result = 1; goto out_free_buffer; } ... out_free_buffer: kfree(buffer); return result; }
在您的特定情况下,它可能如下所示:
int f(...)
{
int ret;
if (Do1()) {
printf("Failed 1");
ret = 1;
goto undo1;
}
...
if (Do5()) {
printf("Failed 5");
ret = 5;
goto undo5;
}
// all good, return here if you need to keep the resources
// (or not, if you want them deallocated; in that case initialize `ret`)
return 0;
undo5:
Undo4();
...
undo1:
return ret;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2849 次 |
| 最近记录: |