5

我目前正在学习 C,想知道以下两段代码的性能是否不同,或者它是否只是一种风格。

查看一些来源,它们具有以下代码:

...
FILE * pFile;
pFile = fopen ("myfile.txt","r");
if (pFile == NULL)
{ some code }
...

虽然我的教授在他的笔记中有以下代码:

...
FILE * pFile
if ((pFile = fopen("myfile.txt","r")) == NULL)
{ some code }
...

只是想知道这是否仅仅是不同程序员的风格偏好,或者将 return/set 行放在 if statmeent 中是否有好处。

4

7 回答 7

5

没有区别。更有经验的程序员有时会使用第二种形式,只是为了节省一行,但它们本质上是相同的。第二个往往更“UNIX-y”,其中大多数函数调用在继续之前检查错误(而不是成功)。

于 2012-04-29T21:13:54.413 回答
1

它们是相同的,因为(pFile = fopen("myfile.txt", "r"))返回pFile,但我个人更喜欢第一个,因为它更明确。

于 2012-04-29T21:15:43.007 回答
1

这两个变体是相等的。它不影响性能。但是,我认为第一个变体更好,因为它使事情更清楚。

于 2012-04-29T21:16:53.707 回答
1

这两个程序是等效的。

有些人喜欢第一种风格,说它更具可读性,有些人喜欢第二种风格,说它更紧凑。

有关信息,请注意在某些编码指南(MISRA是其中之一)中,禁止使用第二种样式。MISRA 禁止在if语句的控制表达式中使用赋值运算符。

于 2012-04-29T21:40:22.273 回答
0

性能上没有区别,但显然第二种更可取。

第一个将尝试打开文件与测试是否成功打开文件分开。

第二个使打开文件和测试是否成功成为一个操作,这正是您不仅应该编码它的方式,也是您应该如何思考它的方式。您根本不应该将它们视为两个独立的操作。打开文件的操作是不完整的,直到/除非您检查了它是否正确打开。

将打开和测试视为两个独立的操作是懒惰的编码,会导致思维草率。不要这样做。

于 2012-04-29T21:30:41.600 回答
0

正如这里所说,这两个部分显然是相同的。然而,我更喜欢第一个,因为它倾向于避免赋值运算符 = 和相等运算符 == 之间的混淆。考虑一个函数foo(arg)返回一个 int 的情况。你会写这样的东西:

int y;

if ((y = foo(x)) == 0) {
    ... some code ...
}

现在,假设您将赋值运算符与相等混淆(顺便说一句,在 if 表达式中很常见):

int y;

if ((y == foo(x)) == 0) {
    ... some code ...
}

由于表达式(y == foo(x))的类型是 int,因此编译器认为上面的代码是合法的 C 代码。这显然会在您的代码中产生错误。

现在,让我们考虑第一个选项:

int y;

y = foo(x);
if (y == 0) {
    ... some code ...
}

显然,现在您不太可能将赋值与相等混淆。此外,即使你写了y == foo(x); 作为语句,编译器将发出警告。

于 2012-04-29T22:33:54.737 回答
0

虽然现有的答案非常好,但关于如何处理 C 语言中的某些内容是否是性能问题,我有几件事要补充。

首先,一种快速检查方法是编译两个版本的代码gcc -O3并比较生成的.o文件。如果它们相同,那么当然不会有任何性能差异(至少与您正在使用的当前编译器/版本不同)。

话虽如此,一个更概念化的方法是问自己两个问题:

  1. 这两段代码是否为所有可能的有效输入变量值定义了完全相同的行为,或者只为您期望的输入定义了相同的行为(甚至只是类似的行为)?

  2. 如果它们定义了完全相同的行为,您认为编译器很容易看到这一点吗?

如果是这样,则“不应该”存在性能差异,因为编译器“应该”将它们编译成它认为是实现所描述行为的最有效方式。当然,有时编译器可能非常愚蠢,所以如果它真的很重要,您可能需要检查一下。

在您的情况下,两个版本的代码都定义了完全相同的行为,我认为您很难找到一个编译器以不同方式编译它们,除非可能完全禁用优化。

于 2012-04-29T22:50:34.053 回答