tags:

views:

1148

answers:

11

Religious arguments aside, in C is ...

if (pointer[i] == NULL) ...

functionally equivalent to ...

if (!pointer[i]) ...

?

Does the later resolve quicker due to absence of a comparison ?

+10  A: 

Almost certainly no difference in performance. I prefer the implicit style of the second, though.

Barry Kelly
A: 

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.

+2  A: 

NULL should be declared in one of the standard header files as such:

#define NULL ((void*)0)

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.

Mark Rushakoff
Actually, for C it's `#define NULL (void *)0`.
avakar
Crap, I had my C/C++ NULLs backwards. I'll update it, thanks for pointing that out.
Mark Rushakoff
C doesn't specify that NULL is ((void*)0), there are platforms where it isn't.
nos
*Typically* it is ((void*)0), though. It sure is on Windows and Linux, and it's more than a fair assumption that the OP is using one of those. He probably wouldn't have asked this if he were using a different platform.
Mark Rushakoff
C allows `NULL` to be defined as `0`.
Johannes Schaub - litb
+20  A: 

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.

Laserallan
+3  A: 

I like the second, other people like the first.

Actually, I prefer a third kind to the first:

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

Because then I:

  • won't be able to miss and just type one "="
  • won't miss the "==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 the null 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.

Thomas
I do not like the readability of this method. In java you might avoid a NullPointerException by using if ("hello".equals(obj.getAttr())) but in this case you have nothing in favor of decreasing the readability...
Yuval A
"Do not compare a pointer with literal zero, however. It will work almost everywhere but is undefined behavior IIRC." <- No that's wrong. What makes you say it's undefined behavior?
Johannes Schaub - litb
Thomas, see http://c-faq.com/null/ptrtest.html. It's perfectly safe to compare a pointer to literal 0.
Andrew Keeton
There may in fact be something valid at (void *)0 on some architectures.
dreamlax
But, NULL is #defined to be 0. So if you're comparing to NULL, you ARE comparing to 0, as far as the compiler is concerned, because the compiler processes not what you type, but the preprocessor's output, and the preprocessor with replace NULL with 0. So the fact that there may be something valid at (void *) 0 is irrelevant. The NULL will be replaced by 0 before the compiler sees it.
smcameron
@Dreamlax you are bloody wrong. You confuse the null pointer value and the null pointer constant. NULL is always valid when defined as 0. Defining it as 0xFFFF of course is never valid. NULL is a null pointer constant. As an exception `(void*)0` is too, in C. When converted to a pointer type, it becomes a null pointer value. This is when it becomes a pointer pointing to some address not equal 0x0. But that has nothing to do with comparing a pointer to 0. This does not compare to address 0. An integer isn't an address.
Johannes Schaub - litb
@dreamlax: from the C99 standard 6.3.2.3: "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function." Which basically says "0 used in a pointer context **is** NULL."
Evan Teran
Also from c++ standard 4.10: (emphasis added) "A null pointer constant is an integral constant expression (5.19) rvalue of integer type that **evaluates to zero**. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type."
Evan Teran
Woah, you know that point where you're so sleepy you start dreaming but you're still awake, and somehow your understanding of the dream world makes sense in the waking world? I think I was there last night. Sorry all.
dreamlax
A: 

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:

#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: Change pointer[0] == NULL to !pointer[0]

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

ctennis
What was your optimization level, and what was your compiler?
Mark Rushakoff
And why are you comparing `char` to `NULL`? The question was about pointers. (Perhaps I'm reading the disassembly wrong, feel free to bash me if it's so.)
avakar
Glad to see, I've read it correctly. :) Turn on optimizations, the code will most likely be same in both tests.
avakar
I changed the code to an array of pointers, but the end result is still the same.
ctennis
Also, putting -O3 in my compile line doesn't change the result (gcc 4.3). Not that it can't be optimized out, of course.
ctennis
Stratch that - optiziming to -O3 does indeed make the output the same.
ctennis
Not only it makes the output the same, using -O2 results in a simple call to `exit(1)`, the comparison is optimized out completely. Note also, that your snippet features undefined behavior (accessing an uninitialized object).
avakar
Yessir, it was just a quick hack. :)
ctennis
-1 for comparing with optimizations disabled. It is misleading and useless.
jalf
You're comparing a character, not a pointer. D'oh!
Norman Ramsey
+1  A: 

Turn on compiler optimization and they're basically the same

tested this on 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

produced no output :)

Charles Ma
Also, passing gcc `-O0` for no optimizations indeed results in different binaries.
Mark Rushakoff
Why are people up-voting this reply? The question is about testing pointers, whereas this example tests an integer. It doesn't make sense to test an integer against NULL; in fact I suspect that you would get a compiler warning if NULL was properly defined and warnings were turned on.
Dipstick
+1  A: 

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

if (!ptr)

than this

if (NULL==ptr)

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.

shimpossible
No, early optimization is bad *especially* if you're trying to squeeze every last hz from your CPU.
jalf
"Micro optimization is also bad, unless you are trying"There, fixed that
shimpossible
A: 
#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      
              ...

Beware, gcc should have bumped out a warning, if not the case compile with -Wall flag on Though, 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 :)

ZeroCool
In the original question 'pointer' is obviously an array of pointers, not chars.
anon
+11  A: 

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 than if (!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.

jalf
I think it does, in fact. I'm sorry if you feel offended by it. I'm not out to attack anyone, just pointing out that this should, if you stop and think about it, be completely and utterly obvious. If two trivial language construct mean the same thing, then they will be compiled the same way.If you want to talk about condescension, how are you better? You are assuming that you, a beginner, is, in about 30 seconds, able to perform better optimizations than the highly experienced developers who wrote your compiler. That seems pretty rude to me too. ;)
jalf
@jalf: If you've never had to use a compiler written by concussed *drunk* ducklings, you can't have been writing software for that long ;-) Luckily, however, natural selection has disposed of most of these horror stories - but I expect a few are still around... More importantly: compiler writers aren't gods - they're fallible like the rest of us, and buggy code still get written. Example: I've recently been dealing with a c++ compiler/rtl where measuring the length of a const string would invoke the copy constructor every time...
Roddy
+4  A: 

Equivalent. It says so in the language standard. And people have the damndest religious preferences!

Norman Ramsey