[comp.lang.c] Is there a NULL pointer to functions?

bxpfac@umiami.ir.miami.edu (05/21/91)

As the subject heading says, is there a NULL pointer to functions?
The program shown below when compiled with gcc generated 
the following message:

In function foo:
warning: ANSI C forbids comparison of `void *' with function pointer

/*-- Program --*/

#define NULL ((void *) 0)

void  foo (void (*fun) (void))
{
      if (fun != NULL)            /* Line with the warning. */
           fun ();   
}

Thanks for any suggestions to fix this.

Bimal / devebw9f@miavax.ir.miami.edu

bxpfac@umiami.ir.miami.edu (05/24/91)

I am not sure if this go posted the first time. Second try!

As the subject heading says, is there a NULL pointer to functions?
The program shown below when compiled with gcc generated 
the following message:

In function foo:
warning: ANSI C forbids comparison of `void *' with function pointer

/*-- Program --*/

#define NULL ((void *) 0)

void  foo (void (*fun) (void))
{
      if (fun != NULL)            /* Line with the warning. */
           fun ();   
}

Thanks for any suggestions to fix this.

Bimal / devebw9f@miavax.ir.miami.edu

bhoughto@pima.intel.com (Blair P. Houghton) (05/26/91)

In article <1991May21.125639.10052@umiami.ir.miami.edu> devebw9f@miavax.ir.miami.edu writes:
>As the subject heading says, is there a NULL pointer to functions?

Yes.

>#define NULL ((void *) 0)
>
>void  foo (void (*fun) (void))
>{
>      if (fun != NULL)            /* Line with the warning. */
>           fun ();   
>}
[...]
>when compiled with gcc generated the following message:

No, when compiled with (at least) 'gcc -ansi -pedantic', it
generates this message.  I almost missed it by leaving
out the '-pedantic'...

>In function foo:
>warning: ANSI C forbids comparison of `void *' with function pointer

Someone should upgrade that message; they were correct, but
incomplete.  ANSI C forbids comparison of function types
with any other types.  It's just a result of the requirement
to compare only "compatible types."  Use a cast to get the
correct type in the right-hand operand:

void  foo (void (*fun) (void))
{
	if ( fun != (void (*) (void))NULL )
	    fun ();
...

				--Blair
				  "And a cast of thousands."

steve@taumet.com (Stephen Clamage) (05/27/91)

bhoughto@pima.intel.com (Blair P. Houghton) writes:

>In article <1991May21.125639.10052@umiami.ir.miami.edu> devebw9f@miavax.ir.miami.edu writes:

>>#define NULL ((void *) 0)
>>void  foo (void (*fun) (void))
>>{
>>      if (fun != NULL)            /* Line with the warning. */
>>           ...
>>warning: ANSI C forbids comparison of `void *' with function pointer

>Use a cast to get the correct type in the right-hand operand:

>	if ( fun != (void (*) (void))NULL )

This isn't really the best solution.  NULL as defined in the standard
ANSI headers is a pointer to an object (data), not pointer to a function.
Where you need a null pointer to a function, use a literal 0, or a 0
cast to the appropriate type when calling a non-prototyped function.

The usage
	if( fun != 0 ) ...
is correct and IMHO more readable.  By "correct", I mean that it is
in strict conformance with ANSI C, and also conforms to early C (K&R1).

When a cast is needed, one can argue about which of these two
	(void (*)(void) NULL)
	(void (*)(void) 0)
is more readable (modulo whitespace).  I don't think either is very
readable, and I might use a typedef for void(*)(void) or a macro
for the whole null pointer.

BTW, the original example shows a programmer #define for NULL.  Since
NULL is a required macro in many ANSI standard headers, it is not a good
idea to #define it yourself.  You may run into a conflict with what is
in the headers on some other system.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

gwyn@smoke.brl.mil (Doug Gwyn) (05/27/91)

In article <1991May21.125639.10052@umiami.ir.miami.edu> devebw9f@miavax.ir.miami.edu writes:
>As the subject heading says, is there a NULL pointer to functions?

Sure, just cast 0 to the appropriate function-pointer type.

>      if (fun != NULL)            /* Line with the warning. */

	if ( fun != (void(*)(void))0 )

bhoughto@pima.intel.com (Blair P. Houghton) (05/28/91)

In article <748@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>bhoughto@pima.intel.com (Blair P. Houghton) writes:
>>Use a cast to get the correct type in the right-hand operand:
>
>>	if ( fun != (void (*) (void))NULL )
>
>This isn't really the best solution.  NULL as defined in the standard
>ANSI headers is a pointer to an object (data), not pointer to a function.

Not so:

"...NULL, which expands to an implementation-defined null
pointer constant..."
(ANSI X3.159-1989, sec. 4.1.5, p. 99, ll. 21-22)

"Such a pointer, called a null pointer constant, is guaranteed to
compare unequal to a pointer to any object OR FUNCTION." [emphasis
mine --Blair]
(Ibid, sec. 3.2.2.3, p. 38, ll. 3-4)

>Where you need a null pointer to a function, use a literal 0, or a 0
>cast to the appropriate type when calling a non-prototyped function.
[...]
>BTW, the original example shows a programmer #define for NULL.  Since
>NULL is a required macro in many ANSI standard headers, it is not a good
>idea to #define it yourself.  You may run into a conflict with what is
>in the headers on some other system.

You have this right, but the specifications of `NULL' and `null pointer
constant' pretty much make

	#define NULL 0

the only valid definition of `NULL,' although there may be others.
Using `(void *) 0' as the value, however, will break the requirement
in section 3.2.2.3, as shown above, since it won't compare legally
at all with a function pointer, while the bare `0' will.

>When a cast is needed, one can argue about which of these two
>	(void (*)(void) NULL)
>	(void (*)(void) 0)

I argue "neither!" for punctuary reasons.  :-)

				--Blair
				  "One of us has done too many
				   Margaritas this weekend, and
				   I've only had six since Friday,
				   so it ain't me.  :-)"

bhoughto@pima.intel.com (Blair P. Houghton) (05/28/91)

In article <4428@inews.intel.com> bhoughto@pima.intel.com (Blair P. Houghton) writes:
>"...NULL, which expands to an implementation-defined null
>pointer constant..."
>(ANSI X3.159-1989, sec. 4.1.5, p. 99, ll. 21-22)
>
>"Such a pointer, called a null pointer constant, is guaranteed to
>compare unequal to a pointer to any object OR FUNCTION." [emphasis
>mine --Blair]
>(Ibid, sec. 3.2.2.3, p. 38, ll. 3-4)

Oops.  Total disconnect of the neural fabric.  The word "constant"
should be removed from the 3.2.2.3 quotation.  The entire
paragraph goes:

	"An integral constant expression with the value 0, or
	 such an expression cast to type void *, is called a
	 null pointer constant.  If a null pointer constant is
	 assigned to or compared for equality to a pointer, the
	 constant is converted to a pointer of that type.  Such
	 a pointer, called a null pointer, is guaranteed to compare
	 unequal to a pointer to any object or function."
	 (Ibid., ll. 1-4)

This doesn't abrogate the necessity that comparisons involve
compatible types, however, nor that bare constants take the
type of the object to which they are assigned or compared.

				--Blair
				  "I get me some new specs, someday... @^O"

volpe@camelback.crd.ge.com (Christopher R Volpe) (05/29/91)

In article <748@taumet.com>, steve@taumet.com (Stephen Clamage) writes:
|>bhoughto@pima.intel.com (Blair P. Houghton) writes:
|>
|>>In article <1991May21.125639.10052@umiami.ir.miami.edu>
devebw9f@miavax.ir.miami.edu writes:
|>
|>>>#define NULL ((void *) 0)
|>>>void  foo (void (*fun) (void))
|>>>{
|>>>      if (fun != NULL)            /* Line with the warning. */
|>>>           ...
|>>>warning: ANSI C forbids comparison of `void *' with function pointer
|>
|>>Use a cast to get the correct type in the right-hand operand:
|>
|>>	if ( fun != (void (*) (void))NULL )
|>
|>This isn't really the best solution.  NULL as defined in the standard
|>ANSI headers is a pointer to an object (data), not pointer to a function.

Is it really defined as a pointer to an object? I always see it defined
as a "null pointer constant", (either "0" or "(void *) 0"), which is 
comparable to any pointer type, no? Section 3.2.2.3 says that a null-pointer-
constant (and "(void *)0" is in fact a null pointer constant) can be assigned
to or compared for equality to any pointer, including function pointers.

                                       
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

hinton@gca.UUCP (Edward Hinton) (05/29/91)

In article <16269@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>In article <1991May21.125639.10052@umiami.ir.miami.edu> devebw9f@miavax.ir.miami.edu writes:
>>As the subject heading says, is there a NULL pointer to functions?
>
>Sure, just cast 0 to the appropriate function-pointer type.
>
>>      if (fun != NULL)            /* Line with the warning. */
>
>	if ( fun != (void(*)(void))0 )

Now I'm going back a ways, but C doesn't necessarily define
NULL as 0, although it's been quite a while since I've seen
a system where it isn't.  However, I recall a system where 0 WAS a
valid address (small model on an 8086 based virtual memory system)
and NULL was defined to be -1.

Although this looks odd, I suggest:

if ( fun != (void(*)(void))NULL )

Then again, it wouldn't necessarily surprise me if a definition
of NULL existed for some C compiler on some machine to define
NULL in a way that it wouldn't like this combination of casts.
I haven't had to do this in ANSI C on any strange implementations yet.

scs@adam.mit.edu (Steve Summit) (05/29/91)

In article <632@gca.UUCP> hinton@gca.UUCP (Edward Hinton) writes:
>Now I'm going back a ways, but C doesn't necessarily define
>NULL as 0, although it's been quite a while since I've seen
>a system where it isn't.  However, I recall a system where 0 WAS a
>valid address (small model on an 8086 based virtual memory system)
>and NULL was defined to be -1.

Regular readers of comp.lang.c recognize the fallacies in this
statement, and I've just sent Ed a copy of the comp.lang.c
frequently-asked questions list, so there should be no need to
comment further on this aspect of the problem.

                                            Steve Summit
                                            scs@adam.mit.edu

gwyn@smoke.brl.mil (Doug Gwyn) (05/30/91)

In article <632@gca.UUCP> hinton@gca.UUCP (Edward Hinton) writes:
>However, I recall a system where 0 WAS a
>valid address (small model on an 8086 based virtual memory system)
>and NULL was defined to be -1.

While an implementation is allowed to make a construct like "((void*)-1)"
act like a null pointer, it is also required (by the standard) to treat
a null pointer constant written by the programmer as "0" (in certain
contexts) or "((void*)0)" as a valid way of denoting a null pointer.
Of course that does not mean that the implementation must internally use
address value 0 to represent a null pointer.  This, while ANY conforming
implementation can define NULL in the standard headers as simply "0",
this has nothing to do with address values.

This topic is covered in the FAQ list, q.v..

mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/02/91)

In article <4429@inews.intel.com>, bhoughto@pima.intel.com (Blair P. Houghton) writes:

[stuff about comparing pointer-to-function to NULL]

> [ANSI X3.159-1989, sec. 3.2.2.3, says]

> 	"An integral constant expression with the value 0, or such an
> 	 expression cast to type void *, is called a null pointer
> 	 constant.  If a null pointer constant is assigned to or
> 	 compared for equality to a pointer, the constant is converted
> 	 to a pointer of that type.  Such a pointer, called a null
> 	 pointer, is guaranteed to compare unequal to a pointer to any
> 	 object or function."

> This doesn't abrogate the necessity that comparisons involve
> compatible types, however, nor that bare constants take the type of
> the object to which they are assigned or compared.

But I believe it *does* require that comparing a function pointer to
(void *)0 convert the null pointer to the appropriate function pointer
type, which the compiler in the original posting was not doing.  (Or at
least was not being silent about.)

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu