在 C 中速度超过风格?

Speed over style in C?

可读性和速度哪个更重要?

示例:

假设您在一种方法中创建了很多资源,如果某些操作失败,您必须释放成功创建的资源。您愿意在一般清理标签中执行此操作,该标签将在操作失败后释放任何资源或释放创建的资源吗?

样式一:

void foo(void)
{
   void* res1, res2, res3;
   res1 = malloc(1);
   if(res1 == NULL)
     return; //operation failed

   res2 = malloc(1);
   if(res2 == NULL)
   {
       free(res1);
       return;
   }

   res3 = malloc(1);
   if(res3 == NULL)
   {
       free(res1);
       free(res2);
       return;
   }
}

样式二:

void foo(void)
{
   void* res1 = NULL, *res2 = NULL, *res3 = NULL;
   res1 = malloc(1);
   if(res1 == NULL)
     goto lbl_clean_up; //operation failed

   res2 = malloc(1);
   if(res2 == NULL)
   {
       goto lbl_clean_up;
   }

   res3 = malloc(1);
   if(res3 == NULL)
   {
       goto lbl_clean_up;
   }
lbl_clean_up:
   {
       if(res1 != NULL)
          free(res1);
       if(res2 != NULL)
          free(res2);
       if(res3 != NULL)
          free(res3);
       return;
}

现在我应该使用样式 1 还是样式 2?样式 2 有更多冗余的 if 语句,但在我看来更具可读性。

我更喜欢第二种方法的变体。使用 goto 跳转到清理代码是一种干净的处理方式。

为了改进这一点,在 NULL 指针上调用 free 是空操作,因此不需要额外的 ifs:

void foo(void)
{
   void* res1 = NULL, *res2 = NULL, *res3 = NULL;
   res1 = malloc(1);
   if(res1 == NULL)
     goto lbl_clean_up; //operation failed

   res2 = malloc(1);
   if(res2 == NULL)
   {
       goto lbl_clean_up;
   }

   res3 = malloc(1);
   if(res3 == NULL)
   {
       goto lbl_clean_up;
   }
lbl_clean_up:
   free(res3);
   free(res2);
   free(res1);

   return;
}

按照分配资源的相反顺序释放资源也是一种很好的做法。您可以在使用多个标签时进一步使用它。例如:

void foo(void)
{
   FILE *f1, *f2, *f3;

   f1 = fopen("infile1", "r");
   if (f1 == NULL)
     goto cleanup1;

   f2 = fopen("infile2", "r");
   if (f2 == NULL)
     goto cleanup2;

   f3 = fopen("outfile", "w");
   if (f3 == NULL)
     goto cleanup3;

   // do something

   close(f3);
cleanup3:
   close(f2);
cleanup2:
   close(f1);
cleanup1:
   return;
}

malloc 失败时的速度差异无关紧要。

样式 1 有一个更严重的问题:多个 returns。这样的函数 (IMO) 更难阅读并且更难更改函数 return type