C:与NULL的比较

除了宗教论点:

  • 选项1:

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

     if (!pointer[i]) ... 

在C中,option1在function上等同于option2?

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

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

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

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

因为那时我:

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

在function上它们是等价的。

即使NULL指针不是“0”(所有零位), if (!ptr)NULL指针进行比较。

以下是不正确的。 它仍然存在,因为有许多注释引用它:不要将指针与文字零比较。 它几乎可以在任何地方工作,但是不明确的行为IIRC。

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

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

当量。 它在语言标准中这么说。 人们有最大的宗教偏好!

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

如果这两种forms是等价的,那么为什么编译器不会将一种forms转换为另一种forms以确保两者同样有效?

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

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

至于问题的第一部分,是的,它们是等价的。 语言标准实际上明确指出了这一点 – 如果指针是非NULL,则指针求值为true;如果指针为NULL,则求值为false,因此两者完全相同。

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

应该在其中一个标准头文件中声明NULL ,如下所示:

 #define NULL ((void*)0) 

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

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

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

 if (!ptr) 

比这个

 if (NULL==ptr) 

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

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

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

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

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

打开编译器优化,它们基本相同

在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 

产生没有输出:)

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

@@ -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  #include  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

 #include  #include  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忽略它…

总是提到你的编译器构建版本:)