why use typecast on NULL?

X

Xiaofeng Ye

Sombody writes:
HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;

why not:
HASH_TABLE *hashed_filenames = NULL;

thanks!
 
M

Mike Wahler

Xiaofeng Ye said:
Sombody writes:
HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;

why not:
HASH_TABLE *hashed_filenames = NULL;

Either way is valid. The former might be considered by some to be more
descriptive. It's a 'style' issue.

-Mike
 
A

Andrey Tarasevich

Xiaofeng said:
Sombody writes:
HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;

why not:
HASH_TABLE *hashed_filenames = NULL;
...

There's no formal reason. Might be some weird coding standard or
personal preference.
 
K

Keith Thompson

Xiaofeng Ye said:
Sombody writes:
HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;

why not:
HASH_TABLE *hashed_filenames = NULL;

No good reason at all. The latter is simpler and clearer.
Casts should be used only when they're actually necessary.
 
D

Dan Pop

In said:
Sombody writes:
HASH_TABLE *hashed_filenames = (HASH_TABLE *)NULL;

why not:
HASH_TABLE *hashed_filenames = NULL;

There is exactly one instance when NULL needs to be cast: when passed as
argument to a variadic function (or a non-prototyped function, but there
is no good reason for not prototyping your functions).

Otherwise, the compiler has enough context information to figure out to
what type the null pointer constant needs to be converted and the
conversion is automatic.

Dan
 
W

William Ahern

There is exactly one instance when NULL needs to be cast: when passed as
argument to a variadic function (or a non-prototyped function, but there
is no good reason for not prototyping your functions).

On OpenBSD NULL is defined as simply `0'. And int's are 32-bits while
pointers 64-bits. The second scenario goes something like:

#include <stdlib.h>
#include <errno.h>

struct something;

struct something *func(void) {
return errno = EINVAL, NULL; /* Should be (struct something *)0
* or (void *)0 or (void *)NULL
* or (struct something *)NULL
*/
}

int main(void) {
func();

return 0;
}
 
A

Arthur J. O'Dwyer

On OpenBSD NULL is defined as simply `0'. And int's are 32-bits while
pointers 64-bits. The second scenario goes something like:

#include <stdlib.h>
#include <errno.h>

struct something;

struct something *func(void) {
return errno = EINVAL, NULL; /* Should be (struct something *)0
* or (void *)0 or (void *)NULL
* or (struct something *)NULL
*/

Is this right? I was all set to pounce on it as incorrect, but
then I hesitated. Is there something magic about the comma operator
in this example? Obviously

return NULL;

is fine --- that's a pointer context, and 'NULL' is converted correctly.
Is William's example actually valid, and if so, why?

(BTW, I would say that's not really a place for casting NULL even if
William is right. I'd rewrite it as
errno = EINVAL; return NULL;
No casts necessary.)

-Arthur
 
W

William Ahern

Arthur J. O'Dwyer said:
Is this right? I was all set to pounce on it as incorrect, but
then I hesitated. Is there something magic about the comma operator
in this example? Obviously

return NULL;

is fine --- that's a pointer context, and 'NULL' is converted correctly.
Is William's example actually valid, and if so, why?

See this thread

http://groups-beta.google.com/group...read/thread/6d46b6a1bb410cb0/bb12342d62b175e8

Specifically, Kevin Easton's remark

result of the comma operator is the type and value of the
_right hand_ expression, not the left.
(BTW, I would say that's not really a place for casting NULL even if
William is right. I'd rewrite it as
errno = EINVAL; return NULL;
No casts necessary.)

I use it often to keep my error detection terse. I don't tend to skimp on
error checking and using braces everytime tends to distract from the common
path.

if (a == NULL || b == NULL)
return errno = EINVAL, -1;

And more importantly, that speaks to me more than using two statements. In a
sense what I am actually returning is a new errno *and* -1.

- Bill
 
C

Chris Torek

Is this right? I was all set to pounce on it as incorrect, but
then I hesitated. Is there something magic about the comma operator
in this example? Obviously

return NULL;

is fine --- that's a pointer context, and 'NULL' is converted correctly.
Is William's example actually valid, and if so, why?

I believe so, yes. The problem is that comma-expressions are not
constant-expressions, according to the Standard. If NULL is defined
as 0 -- which is of course legitimate -- then this line expands to
something like:

return errno = 42, 0;

A comma-expression is not a constant, not even when both its operands
are constants, as in (3,4). (Our expression in question has a
side-effect on the left-hand side, so it would be still be "not a
constant" according to such a rule, not that either C standard has
such a rule.) Since a null pointer constant is obtained only with
an integral *constant* expression with value 0 (possibly with an
attached cast to (void *)), and this zero is not constant, this
must not be a null pointer constant.
(BTW, I would say that's not really a place for casting NULL even if
William is right. I'd rewrite it as
errno = EINVAL; return NULL;
No casts necessary.)

Yes, this is much cleaner for a future maintainer.
 
A

Andrey Tarasevich

William said:
...
On OpenBSD NULL is defined as simply `0'. And int's are 32-bits while
pointers 64-bits. The second scenario goes something like:

#include <stdlib.h>
#include <errno.h>

struct something;

struct something *func(void) {
return errno = EINVAL, NULL; /* Should be (struct something *)0
* or (void *)0 or (void *)NULL
* or (struct something *)NULL
*/
}
...

An expression that contains comma operator or assignment operator is not
a NPC (null pointer constant). Forcing such an expression to pointer
type is not guaranteed to result in NPV (null pointer value). Without a
cast this code is broken. The original one isn't.
 
A

Arthur J. O'Dwyer

Ah yes, the comma operator cannot be used in constant expressions. So
we end up trying to convert the (non-constant-expression) integer 0 to
a pointer type, and failing. You're right. Thanks.

Re: readability, I still maintain that you can have your cake and eat
it too. If I really ended up writing this sort of thing a lot (which I
don't, since I don't use 'errno' to report errors in my own code), I'd
probably use a macro like

#define RETURN_ERRNO(x,y) do { errno=(x); return y; } while (0)

(Pedantic treat: I'm not happy with the macro's name, since it takes a
return value and an errno value, but not in that order. But if I called
it 'ERRNO_RETURN', it would invade the implementation's namespace. And
if I simply reversed the parameters, it would use them in the opposite
order from how they were passed, which seems unintuitive. Quite the
dilemma! :)

-Arthur
 

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

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top