2010-06-13 70 views
2

以下两种方法之一在另一种方法中是否有优势?C变量声明和错误处理优先级的最佳实践

这是第一次测试,fopen是否成功都和然后所有的变量声明发生,以确保它们不会进行,因为它们不能不得不

void func(void) { 
    FILE *fd; 

    if ((fd = fopen("blafoo", "+r")) == NULL) { 
      fprintf(stderr, "fopen() failed\n"); 
      exit(EXIT_FAILURE); 
    } 

    int a, b, c; 
    float d, e, f; 
    /* variable declarations */ 

    /* remaining code */ 
} 

这恰恰相反。所有的变量声明发生,即使fopen失败

void func(void) { 
    FILE *fd; 
    int a, b, c; 
    float d, e, f; 
    /* variable declarations */ 

    if ((fd = fopen("blafoo", "+r")) == NULL) { 
      fprintf(stderr, "fopen() failed\n"); 
      exit(EXIT_FAILURE); 
    } 

    /* remaining code */   
} 

没有第二种方法产生任何额外费用,当fopen失败? 很想听听你的想法!

+1

为什么要优化exit(EXIT_FAILURE)分支的路径?你期望它发生很多? – u0b34a0f6ae 2010-06-13 11:53:47

+1

这只是一个例子来指代一个更一般的结构。 – guest 2010-06-13 11:54:47

+0

[如何处理条件初始化,这是一个很好的做法?](http://stackoverflow.com/questions/16102683/how-is-conditional-initialization-handled-and-is-it-a-good -ractract) – tne 2014-02-23 16:37:57

回答

4

不,它没有任何费用。这两个例子最可能编译成相同的结果二进制文件。因为变量声明没有赋值实际上并不实际 C中的任何东西,它不会生成任何代码。这些变量可用的空间将在需要时由堆栈指针简单地跳过。

1

fopen失败时,应用程序退出,所以没有人真正关心变量是否已初始化。没有成本,因为应用程序已经终止,并且静态分配的内存已经释放。如上所述,内存甚至没有被分配,但是如果你将它们全部设置为默认值,比如0,那么将会有内存。即使你改变了这种行为,也没有额外的成本。

此外,第二个代码可能是可取的,因为它符合C89。

+0

所以它不占用任何额外的时间,对于已经被初始化为空的变量? – guest 2010-06-13 11:50:44

+0

变量初始化适用于编译器,而不是二进制。 – alternative 2010-06-13 11:51:37

+0

当然,迭代数组需要时间,但是在声明变量的地方,不管它们有多“大”,都没有区别。 – 2010-06-13 12:00:12

1

在这两种情况下,在函数的顶部可能会发生同一范围内函数中所有变量的堆栈变量分配,所以任何一种方法都可以。

0

它应该没有什么区别,但是您可以随时比较两个版本的组件输出以确保!

堆栈上的空间总是在函数入口处准备好,可能是为了获得一个很好的函数将变量名映射到编译器/编译器编写器的基本指针+偏移量。至于初始化,它也不应该有任何区别。内容是未定义的,直到在两个版本中写入变量为止。然而,在C++中,当跳过初始化(在你的例子中你没有做的代码)时,你可能会遇到一些问题,但是C++的理由要复杂得多。

1

你的例子中的变量声明在大多数编译器中不会增加额外的开销。他们唯一可能的时候是如果他们有初始化值需要任何非平凡的代码产生。

例如:

void func(const char * filename) { 
    FILE *fd; 
    int a, b, c; 
    size_t z = strlen(filename); 
    float d, e, f; 
    /* variable declarations */ 

    if ((fd = fopen(filename, "+r")) == NULL) { 
      fprintf(stderr, "fopen() failed\n"); 
      exit(EXIT_FAILURE); 
    } 

    /* remaining code */  
    /* Some code that uses z */ 
} 

在这个例子中strlen可以尝试打开文件之前被调用,但它从来没有使用的价值。在fopen之后拨打电话strlen可能会产生更好的代码。但这不是最好的例子,因为编译器经常知道像strlen这样的几个函数是纯粹的函数(没有副作用,只能用它们的参数来产生结果),并且可以将调用移动到以下的strlen,但是您应该明白了。