managing if statements
GCC 4.4.3C89
我有一些函数可以初始化一些硬件并返回true或false。如果为false,则必须按相反的顺序取消初始化。
但是,我的代码看起来非常不整洁,包含了所有的if语句。
例如,每个函数都可以返回"真"或"假"。这是一个样本。正如您所看到的,代码看起来非常不整洁。我只是在寻找任何建议,如何清理它,使它更容易管理,如果可能结痂?
非常感谢您的建议,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | if(init_A() == TRUE) { if(init_B() == TRUE) { if(init_C() == TRUE) { if(init_D() == TRUE) { if(init_E() == TRUE) { /* ALL STARTED OK */ } else { uninit_A(); uninit_B(); uninit_C(); uninit_D(); } } else { uninit_A(); uninit_B(); uninit_C(); } } else { uninit_A(); uninit_B(); } } else { /* Failed to initialize B */ uninit_B(); } } else { /* Failed to start */ } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | if(init_A() != TRUE) { goto EndA; } if(init_B() != TRUE) { goto EndB; } if(init_C() != TRUE) { goto EndC; } if(init_D() != TRUE) { goto EndD; } if(init_E() != TRUE) { goto EndE; } ... return; EndE: uninitD(); EndD: uninitC(); EndC: uninitB(); EndB: uninitA(); EndA: return; |
这是一个很常见的问题,其中"init"步骤对应于
在这种情况下,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | int somefunc() { int retval = ERROR; if (init_A() != TRUE) goto out_a; if (init_B() != TRUE) goto out_b; if (init_C() != TRUE) goto out_c; if (init_D() != TRUE) goto out_d; if (init_E() != TRUE) goto out_e; /* ALL STARTED OK */ /* ... normal processing here ... */ retval = OK; uninit_E(); out_e: uninit_D(); out_d: uninit_C(); out_c: uninit_B(); out_b: uninit_A(); out_a: return retval; } |
我将遍历一个函数指针数组,调用循环中的函数,然后如果该函数返回false,则执行相应的
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | void (*inits[5]) (void); void (*uninits[4]) (void); int main(void) { inits[0] = init_A; inits[1] = init_B; inits[2] = init_C; inits[3] = init_D; inits[4] = init_E; uninits[0] = uninit_A; uninits[1] = uninit_B; uninits[2] = uninit_C; uninits[3] = uninit_D; for(int i = 0; i < 5; i++) { if((*inits[i])() != TRUE) { int j = (i < 4) ? i : 4; while(j--) { (*uninits[j])(); } break; } } return 1; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | BOOL a = FALSE, b = FALSE, c = FALSE, d = FALSE, e = FALSE; if ( (a = init_A()) && (b = init_B()) && (c = init_C()) && (d = init_D()) && (e = init_E()) ) { } else { if ( e ) uninit_E(); if ( d ) uninit_D(); if ( c ) uninit_C(); if ( b ) uninit_B(); if ( a ) uninit_A(); } |
uninit函数按直接顺序调用,如在代码中。如果需要反转顺序,只需更改此顺序。
那是"逆序"?对我来说,逆序是这样的:
1 2 3 4 5 6 7 8 9 | void uninit(int from) { switch (from) { /* ... */ case 3: uninit_C(); /* fall_through */ case 2: uninit_B(); /* fall_through */ case 1: uninit_A(); /* fall_through */ case 0: break; } } |
初始化过程是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int count = 0; if (init_A()) { count++; if (init_B()) { count++; if(init_C()) { count++; if(init_D()) { count++; if(init_E()) { count++; } } } } } if (count == 5) /* ALL OK */; uninit(count); |
如果您的
1 2 3 4 5 6 7 | if (!init_A() || !init_B() || !init_C() || !init_D() ) { uninit_C(); uninit_B(); uninit_A(); return FALSE; } |
您可能正在寻找的是"范围绑定资源管理"。C++传统上使用构造函数/析构函数来实现这一点。但是,通过滥用EDCOX1的7Ω-语句有一种方式(在C99和C++中)有不同的方式。我在这行写了一些东西:用于范围的范围绑定资源管理。
对C的理解有限,如果你决定投反对票,请告诉我原因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #include <stdio.h> int init_a() { return 1; }; // succeed int init_b() { return 1; }; // succeed int init_c() { return 0; }; // fail void uninit_a() { printf("uninit_a() "); } void uninit_b() { printf("uninit_b() "); } void uninit_c() { printf("uninit_c() "); } typedef struct _fp { int (*init)(); void (*uninit)(); } fp; int init() { fp fps[] = { (fp){&init_a, &uninit_a}, (fp){&init_b, &uninit_b}, (fp){&init_c, &uninit_c} }; unsigned int i = 0, j; for(; i < sizeof(fps) / sizeof(fp); ++i) { if(!(*fps[i].init)()) { for(j = 0; j < i; ++j) { (*fps[j].uninit)(); } return -1; } } return 0; } int main() { init(); return 0; } |
输出:
1 2 | uninit_a() uninit_b() |
这与执行原始日志中的代码的顺序相同,但您可能希望将其反转(内部循环)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | int X = 0; if(init_A() == TRUE) { X++; if(init_B() == TRUE) { X++; if(init_C() == TRUE) { X++; if(init_D() == TRUE) { X++; if(init_E() == TRUE) { X++; /* ALL STARTED OK */ } } } } } /* You said reverse order which I took to mean this, * though your did not do it this way. */ switch (X) { case 5: return SUCCESS; case 4: uninit_D(); case 3: uninit_C(); case 2: uninit_B(); case 1: uninit_A(); return FAILURE; } |
我发现自己正在做一些事情来防止自己在代码中出错,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | static int do_A(void); static int do_B(void); static int do_C(void); static int do_D(void); static int do_A(void) { if (init_A() == FALSE) { return FALSE; } if (do_B() == FALSE) { uninit_A(); return FALSE; } return TRUE; } ... static int do_D(void) { return init_D(); } |
所有其他do_u函数都应该与do_u a相似。
我没有编译器来测试这个。但像这样的事情可能奏效?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int (*init[])() = {init_A, init_B, init_C, init_D, init_E}; int (*uninit[])() = {uninit_A, uninit_B, uninit_C, uninit_D, uninit_E}; int main() { initfunction(init, 0) return 0; } void initfunction((*init[])(), pos) { if(init[pos]() == TRUE) initfunction(init, pos++) else return; uninit[pos](); } |