管理if语句

时间:2010-09-14 07:35:27

标签: c

gcc 4.4.3 c89

我有一些初始化某些硬件并返回true或false的函数。如果为false,那么我必须以相反的顺序取消初始化。

但是,我的代码对所有if语句看起来都很不整洁。

例如,每个函数都可以返回true或false。这是一个样本。正如您所看到的,代码看起来非常不整洁。我只是在寻找有关如何清理它以使其更易于管理且可能变得更糟糕的任何建议?

非常感谢任何建议,

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 */
}

10 个答案:

答案 0 :(得分:24)

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;

答案 1 :(得分:8)

这是一个非常常见的问题,其中“init”步骤对应于malloc()lock()之类的内容,“uninit”步骤对应于free()和{{unlock()之类的内容。 1}}。当资源必须严格按照分配的相反顺序解除分配时,尤其是一个问题。

这是goto的使用合理的一种情况:

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;
}

答案 2 :(得分:7)

我会遍历一个函数指针数组,调用循环中的函数,然后如果该函数返回false,则执行相应的uninit_*函数。

以下是一个例子:

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;
}

答案 3 :(得分:6)

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函数按照直接顺序调用,就像在代码中一样。如果需要相反的顺序,只需更改它。

答案 4 :(得分:4)

如果您的uninit_*功能可以检测到他们是否需要做任何事情,您只需:

if (!init_A() || !init_B() || !init_C() || !init_D() )
{
  uninit_C();
  uninit_B();
  uninit_A();
  return FALSE;
}

答案 5 :(得分:4)

这是“逆序”吗?对我来说,逆向订单是这样的:

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;
    }
}

初始化过程就像这样

    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);

答案 6 :(得分:2)

对C在这里工作的理解有限,如果你决定进行投票,请告诉我原因。

#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()\n"); }
void uninit_b() { printf("uninit_b()\n"); }
void uninit_c() { printf("uninit_c()\n"); }

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;
}

输出:

uninit_a()
uninit_b()

这与原始帖子中的代码执行的顺序相同,但您可能想要将其反转(内部循环)。

答案 7 :(得分:2)

您可能正在寻找的是“范围限制资源管理”。 C ++传统上使用构造函数/析构函数来实现。但是有一种方法可以通过滥用for语句来区别对待(在C99和C ++中)。我在这里写了一些内容: scope bound resource management with for scopes

答案 8 :(得分:1)

我没有编译器来试试这个。但是这样的事可能有用吗?

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]();
}

答案 9 :(得分:1)

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;
}

我发现自己正在做的事情是防止自己在这样的代码中出错:

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_函数应该与do_A类似。