How should I test for a null pointer?

B

Ben Bacarisse

In other languages (where zero is true and non zero is false), I test booleans
in this manner.

if booleanvalue == TRUE

or:

if booleanvalue != TRUE

You should name and shame. No language should be that clumsy!
But in languages where zero is false, and non zero is true, then this form
is not suitable:

# FALSE and NOT FALSE is just nasty
if booleanvalue != FALSE # This looks really nasty. I wouldn't do
that

You should never need to. 'if booleanvalue' should work in all but
the clumsiest programming languages.
In assembly language (on the 8086) we have:

jz label # jump if zero
jnz label # jump if non zero

(We can also easily use single bits to store booleans, which is rather nice.)

In C, I have implemented a kludge for boolean testing in the form of macros
istrue and isfalse:

if istrue(booleanvalue) {dosomething}

and

if isfalse(booleanvalue) {dosomething}

What benefit do these macros provide? You don't show them and I can't
guess.
 
M

Mark Hobley

Ben Bacarisse said:
What benefit do these macros provide? You don't show them and I can't
guess.

They just provide a way of putting the words true or false within the
expression for the benefit of a casual human* debugger.

#define istrue(arg) (arg)
#define isfalse(arg) !(arg)

(It just saves the guy from having to think ... "hmmm, is true expressed as
a zero or non-zero value in this language?")

It seems odd to me to have a convention of zero to represent successful
completion, but to then use the value as false:

# This logic does not work in C, because success is false
if thisfunctionsucceeds() then
# blah blah blah
else
print "Damn! It's fucked."
# Note that our error handler is nicely positioned as a footnote
# below the main body of the the code
endif

That doesn't work in C, which means that to a human* reading the code, the
our error handler is now interrupting the flow as the program is read from
top down.

if thisfunctionfails() {

/* The error handler is in right in your face at the top of the code */
printf("Damn! It's fucked")

} else {

/* blah blah blah */
}

In assembly language we use a goto, but some programmers do not like these.

# Although assembly language also uses the same convention as C, the
# one line goto, and the lack of braces, makes the jump to the error
# handler unobtrusive

call ourfunction
jnz errorhandler # We use a goto here
# blah blah blah

Trying a similar trick in C gives us

if thisfunctionfails() {
goto errorhandler; /* It still looks messy */
} else {
/* blah blah blah */
}

Or we can have a really horrible construct:

if thisfunctionfails() { goto errorhandler; } else {
blah blah blah
}

Note that blah blah blah is based on success, but the if statement above was
testing for failure! Yuck !

* Although I am human, I don't alway appear to be.

Mark.
 
N

Nick Keighley

Pretty much.  Sometimes it's "Thank you, but that's the intended behavior"
or "Thank you, but your usage is incorrect", but in general, I try to err
on the side of fixing anything that looks like a bug.

Thank you but...

....that's a well known problem
....its always done that
....why would anyone do that?
....customers don't do that
....that's bound to happen if you do that
....we'll change the handbook
....that's so old we should just close it


my time in system test wasn't wasted
 
B

Ben Bacarisse

They just provide a way of putting the words true or false within the
expression for the benefit of a casual human* debugger.

#define istrue(arg) (arg)
#define isfalse(arg) !(arg)

(It just saves the guy from having to think ... "hmmm, is true expressed as
a zero or non-zero value in this language?")

Ah. Sorry, but I think that's a bad idea. It all comes under the
category of tying to guess what kind of information deficit the reader
has. Why assume they don't know one of the most basic things about
the language they are reading? Why do anything to delay them
acquiring this knowledge? (The argument seems to be they will be
happy to skip over the newly clarified conditions rather figure out
how C does ifs).

For readers who do know what a C 'if' does you add a level of
obfuscation. The reader immediately thinks "what is this programming
doing with C's idea of true/false conditions that they need a macro?
Oh, I see, nothing at all".

All languages have foibles, but C also has a macro processor and the
combination tempts people learning C to use the latter to tidy up the
former. I don't think that is ever a good idea.
It seems odd to me to have a convention of zero to represent successful
completion, but to then use the value as false:

# This logic does not work in C, because success is false
if thisfunctionsucceeds() then
# blah blah blah
else
print "Damn! It's fucked."
# Note that our error handler is nicely positioned as a footnote
# below the main body of the the code
endif

OK, you want the error case second. I'll go with that for the moment...
That doesn't work in C, which means that to a human* reading the code, the
our error handler is now interrupting the flow as the program is read from
top down.

if thisfunctionfails() {

/* The error handler is in right in your face at the top of the code */
printf("Damn! It's fucked")

} else {

/* blah blah blah */
}

So why write it that way if you want the error case second? This is
so obious a question that I must have missed your point. What is it
about C that makes you think you forced into doing it the way you
don't like?
In assembly language we use a goto, but some programmers do not like these.

# Although assembly language also uses the same convention as C, the
# one line goto, and the lack of braces, makes the jump to the error
# handler unobtrusive

call ourfunction
jnz errorhandler # We use a goto here
# blah blah blah

Trying a similar trick in C gives us

if thisfunctionfails() {
goto errorhandler; /* It still looks messy */
} else {
/* blah blah blah */
}

Or we can have a really horrible construct:

if thisfunctionfails() { goto errorhandler; } else {
blah blah blah
}

All you C ifs are missing brackets round the condition, by the way.

What is it that you have against

if (!thisfunctionfails()) {
blah blah blah
}
else /* error case */;

? Personally, I'd write the function to be "positive" i.e. to return
non-zero on success, but I agree that there are some written the other
way round. These should not have a name that suggests they might be
tested logically.

<snip>
 
D

Dr Malcolm McLean

It seems odd to me to have a convention of zero to represent successful
completion, but to then use the value as false:
So I do it like this

err = functionthatmightfail(str, x, y);
if(err)
{
/* clean up failure */
}

The problem with

if( functionthatmighfail(str, x, y) )

is that it makes it look as if the purpose of functionthatmightfail()
is to return a value. In the first case it's obvious that it's
modifying the string str based on some values x, y.
 
S

Seebs

Thank you but...

...that's a well known problem
...its always done that
...why would anyone do that?
...customers don't do that
...that's bound to happen if you do that
...we'll change the handbook
...that's so old we should just close it

my time in system test wasn't wasted

Ugh.

I still remember the horrors of doing testing for people who Just
Didn't Care. "When you use this feature, the software coredumps."
"Don't use that feature." "$BIG_CUSTOMER is already using the feature
in production, and they want it fixed." "We've removed it from the
next version."

The scary thing? The average cost of a program crash was somewhere
around $50k. This did not appear to factor into evaluations, though,
because it was *customers* paying the $50k, not *developers*.

-s
 
S

Seebs

Thank you but...

...that's a well known problem
...its always done that
...why would anyone do that?
...customers don't do that
...that's bound to happen if you do that
...we'll change the handbook
...that's so old we should just close it

my time in system test wasn't wasted

Ugh.

I still remember the horrors of doing testing for people who Just
Didn't Care. "When you use this feature, the software coredumps."
"Don't use that feature." "$BIG_CUSTOMER is already using the feature
in production, and they want it fixed." "We've removed it from the
next version."

The scary thing? The average cost of a program crash was somewhere
around $50k. This did not appear to factor into evaluations, though,
because it was *customers* paying the $50k, not *developers*.

-s
 
H

Hamiral

Mark said:
if istrue(booleanvalue) {dosomething}

and

if isfalse(booleanvalue) {dosomething}

That reminds me that (sorry it's Pascal not C) ;)


(*---------------------------------------------------------------------------
Procedure: IsTrue
Author: jed
Date: 26-Aug-2003
Description: useful for determining the boolean result of an expression
---------------------------------------------------------------------------:*)
function IsTrue(Expression: TExpression): Boolean;
var
ResultHasBeenSet: Boolean;
begin
Result:=(Random(2)=0)=True;
ResultHasBeenSet:=False;

// if the expression is true then the result will be true, otherwise
(since the
// expression couldn't be true) the result will be false. There are
no other
// mathematical possibilities
begin
if (Expression=True) then
begin
Result:=True;
ResultHasBeenSet:=True;
end;

if (Expression=False) then
begin
Result:=False;
ResultHasBeenSet:=True;
end;
end;

// need to set the result if it hasn't been set yet, we'll randomly
decide true or false
// because there should be no bias.
if IsTrue(ResultHasBeenSet)=IsTrue(0=1)
then Result:=((Random(2)=Random(2))=True)
else Result:=(Result=True);

// P.S.
// This function could also be adapted to tell you if some
expression is false
// by prefixing the expression (or the result) with the 'not'
operator. You can
// find out more about the 'not' operator in the online help.
end;


Ham
 
D

Dr Malcolm McLean

The scary thing?  The average cost of a program crash was somewhere
around $50k.  This did not appear to factor into evaluations, though,
because it was *customers* paying the $50k, not *developers*.
That's the way captialism works. The perceived value of the product,
not the actual value to customers, is what determines the price ypu
get for it. So if customers' accpunting system isn't good enough to
pick up the money he loses on crashes, he gets cheaper buggy software
rather than more expensive reliable stuff.
(This reaches an extreme when the customer is the consumer. Virtually
all the major consumer goods companies have far more equity in brands
than in physical plant. Often more money goes on marketing the product
than in manufacturing it. The associations that the marketing people
create between the product and the customers' aspirations almost never
have any basis in physical reality - the same beer can be a womans'
drink in Europe, a manly drink in America.)
 
N

Nick Keighley

You should never need to.  'if booleanvalue' should work in all but
the clumsiest programming languages.

not all programming languages have booleans. Consider Coral-66

IF finished = TRUE THEN
terminate (link);

(syntax from memory!)
 
B

BruceS

?  Personally, I'd write the function to be "positive" i.e. to return
non-zero on success, but I agree that there are some written the other
way round.  These should not have a name that suggests they might be
tested logically.

As one more side-topic: I almost always prefer the reverse. If a
function succeeds, I don't care exactly *why* it succeeded. If it
fails, the reason for failure may be important and dictate the
behavior of the calling function---at least to the extent of logging
or reporting the error code. Of course, sometimes the fact of failure
is also enough (e.g. malloc and friends) to determine response.
I recall a system (VMS?) where the standard was to use even/odd to
indicate success/failure. We had a macro to weed out the success
codes, and universally ignored them. The errors codes, however, got
used.
 
B

Ben Bacarisse

BruceS said:
As one more side-topic: I almost always prefer the reverse. If a
function succeeds, I don't care exactly *why* it succeeded. If it
fails, the reason for failure may be important and dictate the
behavior of the calling function---at least to the extent of logging
or reporting the error code. Of course, sometimes the fact of failure
is also enough (e.g. malloc and friends) to determine response.

That's a perfectly sound way of doing things but it does tend to
prioritise the status rather than the value a function computes.
Computed results typically have to be returned via a pointer. When I
need an informative error status, I prefer that to the thing returned
via a pointer.

Yours is the style used by *nix system calls, but that is for sound
technical reasons (though they may now be historical) -- only a simple
result could be returned as the value, and the kernel got to validate
pointers used for larger computer values. Without these restrictions,
it would not be my first choice.

<snip>
 
N

Nobody

which is why I don't use the !ptr form, I find it too error prone...

Odd; That's why I don't use ptr==0 or ptr!=0.

"!=0" is a postfix no-op, while "==0" is a postfix negation. But (as
Seebs demonstrated) it's very easy to confuse the two.

If I want to invert "x", I'll write "!x"; if I want "x" without any
inversion, I'll just write "x".

If the value being tested was an actual C99 "bool", would you write:

if (x != false)
and:
if (x == false)

in preference to:

if (x)
and:
if (!x)

?

I wouldn't, and I wouldn't do it for pointers, either.
 
F

Flash Gordon

Nick said:
not all programming languages have booleans. Consider Coral-66

IF finished = TRUE THEN
terminate (link);

(syntax from memory!)

You must have been using a modern variant since you did not put single
quotes around the keyboards! Now stop giving me nightmares.
 
K

Keith Thompson

Nobody said:
If the value being tested was an actual C99 "bool", would you write:

if (x != false)
and:
if (x == false)

in preference to:

if (x)
and:
if (!x)

?

Certainly not.
I wouldn't, and I wouldn't do it for pointers, either.

That's where we differ. I wouldn't write "if (ptr == 0)", as you
mention in the text that I snipped; I'd write "if (ptr == NULL)".

I find "if (x)" clearer than "if (x != false)", at least if x is
logically a condition (i.e., it has a better name than "x").

I find "if (ptr != NULL") clearer than either "if (ptr != 0)"
or "if (ptr)".

YMMV, of course.
 
N

Nick Keighley

I recall a system (VMS?) where the standard was to use even/odd to
indicate success/failure.

it was VMS. I think an even value was an error so a program that
returned 0 caused a bizzre error to be reported by the shell. This was
a problem for some VMS C compilers.
 
A

August Karlstrom

Keith said:
That's where we differ. I wouldn't write "if (ptr == 0)", as you
mention in the text that I snipped; I'd write "if (ptr == NULL)".

I find "if (x)" clearer than "if (x != false)", at least if x is
logically a condition (i.e., it has a better name than "x").

I find "if (ptr != NULL") clearer than either "if (ptr != 0)"
or "if (ptr)".

YMMV, of course.

I agree 100%.

Clear writing:

if (done) ...

if (p == NULL) ...

if (n != 0) ...


Obscure writing:

if (done != 0) ...

if (!p) ...

if (n) ...


/August
 
A

August Karlstrom

Nobody said:
If the value being tested was an actual C99 "bool", would you write:

if (x != false)
and:
if (x == false)

in preference to:

if (x)
and:
if (!x)

No, I think we should write

if ((x != false) != false)

and

if ((x == false) != false)

....just to be sure.


/August
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,609
Members
45,253
Latest member
BlytheFant

Latest Threads

Top