C:与NULL的比较

时间:2009-08-16 11:09:42

标签: c performance null comparison

除了宗教论点:

  • 选项1:

    if (pointer[i] == NULL) ...
    
  • 选项2:

    if (!pointer[i]) ...  
    

在C中,option1在功能上等同于option2吗?

由于没有比较,后者会更快解决吗?

11 个答案:

答案 0 :(得分:33)

我更喜欢显式样式(第一版)。很明显,有一个指针涉及,而不是一个整数或其他东西,但它只是一个风格的问题。

从性能的角度来看,它应该没有区别。

答案 1 :(得分:31)

等效。它在语言标准中这样说。人们有该死的宗教偏好!

答案 2 :(得分:19)

假设编译器编写者至少具有最低智能度通常很有用。您的编译器由混淆的小鸭子编写。它由人类编写,具有多年的编程经验,并且花了数年时间研究编译器理论。这并不意味着您的编译器是完美的,并且总是最了解,但它 意味着它完全能够处理琐碎的自动优化。

如果这两种形式是等价的,那么为什么编译器不会只将一种形式翻译成另一种形式以确保两者同样有效?

如果if (pointer[i] == NULL)慢于if (!pointer[i]),编译器是否只会将其更改为第二种更有效的形式?

所以不,假设它们是等价的,它们同样有效。

至于问题的第一部分,是的,它们是等同的。语言标准实际上在某处显式地表明了这一点 - 如果指针是非NULL,则指针求值为true;如果指针为NULL,则求值为false,因此两者完全相同。

答案 3 :(得分:17)

我喜欢第二种,其他人喜欢第一种。

实际上,我更喜欢第三种:第一种:

if (NULL == ptr) {
   ...
}

因为那时我:

  • 将无法错过,只需键入一个“=”
  • 如果条件很长(多行),
  • 将不会错过“== NULL”并将其误认为相反

在功能上它们是等价的。

即使NULL指针不是“0”(全零位),if (!ptr)也会与NULL指针进行比较。

以下内容不正确。它仍然存在,因为有很多评论指的是: 但是,不要将指针与文字零进行比较。它几乎可以在任何地方使用,但是未定义的行为IIRC。

答案 4 :(得分:9)

几乎可以肯定没有性能差异。不过,我更喜欢第二种的隐含风格。

答案 5 :(得分:3)

NULL应该在其中一个标准头文件中声明:

#define NULL ((void*)0)

无论哪种方式,您都要与零进行比较,编译器应该以相同的方式进行优化。每个处理器都有一些“优化”或操作码,用于与零进行比较。

答案 6 :(得分:1)

早期优化很糟糕。微优化也很糟糕,除非你试图从你的CPU中挤出最后一点Hz,没有必要这样做。正如人们已经表明的那样,编译器无论如何都会优化你的大部分代码。

最好使您的代码尽可能简洁易读。如果这更具可读性

if (!ptr)

比这个

if (NULL==ptr)

然后使用它。只要每个将阅读您的代码的人都同意。

我个人使用完全定义的值(NULL == ptr),因此很清楚我要检查的是什么。键入的时间可能会更长,但我可以轻松阅读。我认为!ptr很容易错过!如果快速阅读。

答案 7 :(得分:0)

这实际上取决于编译器。如果大多数现代C编译器没有为您描述的特定场景生成几乎相同的代码,我会感到惊讶。

让你的编译器为每个场景生成一个汇编列表,你可以回答你自己的问题(针对你的特定编译器:)。

即使他们 不同,性能差异也可能与实际应用无关。

答案 8 :(得分:0)

启用编译器优化,它们基本相同

在gcc 4.3.3

上测试了这个
int main (int argc, char** argv) {
   char c = getchar();
   int x = (c == 'x');
   if(x == NULL)
      putchar('y');
   return 0;
}

VS

int main (int argc, char** argv) {
   char c = getchar();
   int x = (c == 'x');
   if(!x)
      putchar('y');
   return 0;
}


gcc -O -o test1 test1.c
gcc -O -o test2 test2.c


diff test1 test2

没有输出:)

答案 9 :(得分:-2)

我做了一个程序集转储,发现了两个版本之间的区别:

@@ -11,8 +11,7 @@
pushl %ecx
subl $20, %esp
movzbl -9(%ebp), %eax
- movsbl %al,%eax
- testl %eax, %eax
+ testb %al, %al

看起来后者实际上会生成一条指令而第一条生成两条指令,但这是非常不科学的。

这是gcc,没有优化:

test1.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{ 
  char *pointer[5];

if(pointer[0] == NULL) {
  exit(1);
}

exit(0);

}

test2.c:将pointer[0] == NULL更改为!pointer[0]

gcc -s test1.c,gcc -s test2.c,diff -u test1.s test2.s

答案 10 :(得分:-2)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{   
  char pointer[5];  
  /* This is insense you are comparing a pointer to a value */   
  if(pointer[0] == NULL) {     
    exit(1);
  } 
  ...
}

=>           ...    
  movzbl    9(%ebp), %eax  # your code compares a 1 byte value to a signed 4 bytes one 
  movsbl    %al,%eax        # Will result in sign extension...
  testl  %eax, %eax      
              ...

请注意,gcc应该发出警告,如果不是这种情况,请使用-Wall标志进行编译 但是,您应该始终编译为优化的gcc代码。 顺便说一下,在你的变量之前加上volatile关键字,以避免gcc忽略它......

始终提及您的编译器构建版本:)