C:与 NULL 比较
抛开宗教争论不谈:
选项1:
if (指针[i] == NULL) ...
选项2:
if (!pointer[i]) ...
在C中,选项1在功能上等同于选项2吗?
由于没有比较,后者是否解决得更快?
Religious arguments aside:
Option1:
if (pointer[i] == NULL) ...
Option2:
if (!pointer[i]) ...
In C is option1 functionally equivalent to option2?
Does the later resolve quicker due to absence of a comparison ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
我更喜欢明确的风格(第一个版本)。 很明显,涉及的是一个指针,而不是整数或其他东西,但这只是风格问题。
从性能的角度来看,这应该没有什么区别。
I prefer the explicit style (first version). It makes it obvious that there is a pointer involved and not an integer or something else but it's just a matter of style.
From a performance point of view, it should make no difference.
相等的。 语言标准里是这么说的。 人们有最的宗教偏好!
Equivalent. It says so in the language standard. And people have the damndest religious preferences!
我喜欢第二个,其他人喜欢第一个。
实际上,我更喜欢第三种而不是第一种:
因为那样我:
=
== NULL
并且如果条件很长(多行),则将其误认为相反。在功能上,它们是等效的。
即使
NULL
指针不是“0”(全零位),if (!ptr)
也会与NULL
指针进行比较。以下说法不正确。 它仍然在这里,因为有很多评论提到它:
但是,不要将指针与文字零进行比较。 它几乎在任何地方都可以工作,但它是未定义的行为 IIRC。
I like the second, other people like the first.
Actually, I prefer a third kind to the first:
Because then I:
=
== NULL
and mistake it for the opposite if the condition is long (multiple lines)Functionally they are equivalent.
Even if a
NULL
pointer is not "0" (all zero bits),if (!ptr)
compares with theNULL
pointer.The following is incorrect. It's still here because there are many comments referring to it:
Do not compare a pointer with literal zero, however. It will work almost everywhere but is undefined behavior IIRC.
假设编译器编写者至少具有最低限度的智力通常是有用的。 您的编译器不是由脑震荡的小鸭编写的。 它是由具有多年编程经验和多年研究编译器理论的人类编写的。 这并不意味着您的编译器是完美的,并且总是知道最好的,但它确实意味着它完全有能力处理琐碎的自动优化。
如果这两种形式是等效的,那么为什么编译器不将一种形式转换为另一种形式以确保两者同样有效?
如果
if (pointer[i] == NULL)
比if (!pointer[i])
慢,编译器是否会将其更改为第二个,更多高效的形式?所以不,假设它们是等效的,那么它们的效率是相同的。
至于问题的第一部分,是的,它们是等价的。 语言标准实际上在某处明确地说明了这一点——如果指针为非 NULL,则其计算结果为 true,如果为 NULL,则为 false,因此两者完全相同。
It is often useful to assume that compiler writers have at least a minimum of intelligence. Your compiler is not written by concussed ducklings. It is written by human beings, with years of programming experience, and years spent studying compiler theory. This doesn't mean that your compiler is perfect, and always knows best, but it does mean that it is perfectly capable of handling trivial automatic optimizations.
If the two forms are equivalent, then why wouldn't the compiler just translate one into the other to ensure both are equally efficient?
If
if (pointer[i] == NULL)
was slower thanif (!pointer[i])
, wouldn't the compiler just change it into the second, more efficient form?So no, assuming they are equivalent, they are equally efficient.
As for the first part of the question, yes, they are equivalent. The language standard actually states this explicitly somewhere -- a pointer evaluates to true if it is non-NULL, and false if it is NULL, so the two are exactly identical.
请注意,如果不是使用
-Wall
标志进行编译,则 gcc 应该会发出警告不过,您应该始终编译为优化的 gcc 代码。
顺便说一句,在你的变量前面加上 volatile 关键字,以避免 gcc 忽略它......
总是提及你的编译器构建版本:)
Beware, gcc should have bumped out a warning, if not the case compile with
-Wall
flag onThough, you should always compile to optimized gcc code.
BTW, precede your variable with volatile keyword in order to avoid gcc from ignoring it...
Always mention your compiler build version :)
几乎可以肯定,性能没有差异。 不过,我更喜欢第二种含蓄的风格。
Almost certainly no difference in performance. I prefer the implicit style of the second, though.
NULL
应该在标准头文件之一中声明,如下所示:因此,无论哪种方式,您都在与零进行比较,并且编译器应该以相同的方式优化两者。 每个处理器都有一些用于与零进行比较的“优化”或操作码。
NULL
should be declared in one of the standard header files as such:So either way, you are comparing against zero, and the compiler should optimize both the same way. Every processor has some "optimization" or opcode for comparing with zero.
早期的优化是不好的。 微观优化也很糟糕,除非你试图从 CPU 中榨取最后一点赫兹,否则这样做是没有意义的。 正如人们已经表明的那样,编译器无论如何都会优化大部分代码。
最好使您的代码尽可能简洁和可读。 更具可读性,
如果这比这
那么就使用它。 只要将阅读您的代码的每个人都同意。
就我个人而言,我使用完全定义的值(NULL==ptr),因此很清楚我要检查的内容。 打字可能会更长,但我可以轻松阅读。 我认为 !ptr 很容易被错过! 如果读得快的话。
Early optimization is bad. Micro optimization is also bad, unless you are trying to squeeze every last bit of Hz from your CPU, there is no point it doing it. As people have already shown, the compiler will optimize most of your code away anyways.
Its best to make your code as concise and readable as possible. If this is more readable
than this
then use it. As long as everyone who will be reading your code agrees.
Personally I use the fully defined value (NULL==ptr) so it is clear what I am checking for. Might be longer to type, but I can easily read it. I'd think the !ptr would be easy to miss ! if reading to quickly.
这实际上取决于编译器。 如果大多数现代 C 编译器没有为您描述的特定场景生成几乎相同的代码,我会感到惊讶。
让您的编译器为每个场景生成一个程序集列表,您可以回答您自己的问题(针对您的特定编译器:))。
即使它们不同,性能差异在实际应用中也可能无关紧要。
It really depends on the compiler. I'd be surprised if most modern C compilers didn't generate virtually identical code for the specific scenario you describe.
Get your compiler to generate an assembly listing for each of those scenarios and you can answer your own question (for your particular compiler :)).
And even if they are different, the performance difference will probably be irrelevant in practical applications.
打开编译器优化,它们基本上是相同的,
在 gcc 4.3.3 上测试
与
没有产生输出:)
Turn on compiler optimization and they're basically the same
tested this on gcc 4.3.3
vs
produced no output :)
我做了一个程序集转储,发现了两个版本之间的差异:
@@ -11,8 +11,7 @@
推 %ecx
低于 20 美元,%esp
movzbl -9(%ebp), %eax
- movsbl %al,%eax
- testl %eax, %eax
+ testb %al, %al
看起来
后者实际上生成了一条指令,而第一个生成了两条指令,但这非常不科学。
这是 gcc,没有优化:
test1.c:
test2.c: 将
pointer[0] == NULL
更改为!pointer[0]
gcc -s test1.c, gcc -s test2.c, diff -u test1.s test2.s
I did a assembly dump, and found the difference between the two versions:
@@ -11,8 +11,7 @@
pushl %ecx
subl $20, %esp
movzbl -9(%ebp), %eax
- movsbl %al,%eax
- testl %eax, %eax
+ testb %al, %al
It looks like the latter actually generates one instruction and the first generates two, but this is pretty unscientific.
This is gcc, no optimizations:
test1.c:
test2.c: Change
pointer[0] == NULL
to!pointer[0]
gcc -s test1.c, gcc -s test2.c, diff -u test1.s test2.s