rationalcoder
rationalcoder

Reputation: 1687

Can I reliably set a function pointer to NULL in C and C++?

In P.J. Plauger's book, The Standard C Library, he warns about assigning a function pointer to NULL.

Specifically, he says this:

The macro NULL serves as an almost-universal null pointer constant. You use it as the value of a data-object pointer that should point to no data object declared (or allocated) in the program. As I mentioned on page 216, the macro can have any of the following definitions 0, 0L, or (void *)0.

The last definition is compatible with any data object pointer. It is not, however, compatible with a function pointer. That means you cannot write

int (*pfun) (void) = NULL; /* WRONG */

The translator may complain that the expression type is incompatible with the data object you wish to initialize.

He goes on to say that:

...There is no guarantee, however, that a pointer to void has the same representation as any other (non-character) pointer. It isn't even assignment compatible with function pointers. That means that you can't write NULL as a universal null-pointer constant. Nor can you safely use it as an argument expression in place of an arbitrary data-object pointer.

I have been assigning function pointers to NULL for quite some time without any problems, and I am wondering if it isn't portable.

Specifically:

void (*test)() = NULL => compiles fine with both gcc and g++

void (*test)() = 0 => compiles fine with both gcc and g++

void (*test)() = (void*)0 => produced an invalid conversion error in both gcc and g++

EDIT: void (*test)() = (void*)0compiles fine in gcc, I was using a file with a .cpp extension... Still, will it always compile, despite Plauger saying that assigning a function pointer to NULL is wrong?

The part I don't understand is the definition of NULL in my stddef.h:

#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL     /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0) // this line confuses me
#else   /* C++ */
#define NULL 0
#endif  /* C++ */
#endif  /* G++ */
#endif  /* NULL not defined and <stddef.h> or need NULL.  */
#undef  __need_NULL

This seems to be defining NULL to be 0 in C++ and ((void *)0) in C. Is it really, or is it being defined as __null?

If so, why does assigning to NULL work all the time, even though assigning to (void*)0, according to Plauger, is "wrong"?**

I am interested in C89**

Upvotes: 23

Views: 25200

Answers (2)

ouah
ouah

Reputation: 145839

 int (*pfun) (void) = NULL;  

It is actually valid.

The C rules of assignment says that:

(Note that's an initialization here but the same type of constraints and conversions as for simple assignment apply.)

(C99, 6.5.16.1 Simple assignment p1 Constraints) "One of the following shall hold: [...] — the left operand is a pointer and the right is a null pointer constant;"

and

(C99, 7.17p3) "The macros are NULL which expands to an implementation-defined null pointer constant;"

So assigning a null pointer constant to any pointer (object pointer, function pointer or void *) is allowed by C. Note that Plauger's book refers to C89 when he mentions Standard C but the wording of the assignment constraints are the same in C89.

Upvotes: 15

user743382
user743382

Reputation:

void (*test)() = (void*)0 => produced an invalid conversion error in both gcc and g++

GCC detects the language based on the file extension. Compiling a .cc file with GCC will invoke the C++ compiler, not the C compiler.

Try it with a C source file and you'll see this is accepted. As it should be, as it's allowed by the standard.

If so, why does assigning to NULL work all the time, but assigning to (void*)0 not?

NULL isn' t allowed to be defined as ((void*)0) in C++ mode. In C++ mode, it must be defined as either an integral constant with value 0, or as nullptr. Either can be converted to any function pointer type.

Can I always reliably set a function pointer to NULL in C and C++?

Yes, in any conforming C or C++ implementation this will work.

Upvotes: 11

Related Questions