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忽略它…
总是提到你的编译器构建版本:)