It may appear to some that these two forms are equivalent and interchangeable. They may generate the same code, but have different meanings to a human reader. Both have their place.
Suppose we have an object X.
I am not telling you what X is. It might be a number, might be a pointer, might be something that I might think of either way.
It is the kind of object that you might correctly or incorrectly see coded either way.
Let's look ..
if (X == 0) {
Read it:
“if X is equal to zero”
if (!X) {
Read it:
“if not X”
Decision on which form to use?
Read it. Which fits better with what you really mean to say?
Now a specific example.
The object name is “size”.
if (size == 0) {
Read it:
“if size is equal to zero”
if (!size) {
Read it:
“if not size”
What does this mean?
“if there is no size”??
“if we don't know the size”??
“if we don't have a size”??
In this case, the first (size==0) most clearly expresses what I believe the meaning of the statement is.
Now another specific example.
The object name is “empty”
if (empty == 0) {
Read it:
“if empty is equal to zero”
if (!empty) {
Read it:
“if not empty”
Here the second (!empty) more clearly expresses the intent, so that's what I use.