POSIX requires (I think) that function pointers can be stored in a variable of type void* and/or passed to functions expecting a void* argument, even though this is strictly non-standard.
My question is this: if I test such a variable/argument for NULL
-ness, if (!(variable or argument))
say, and the result is true
, does that necessarily mean that the function-pointer is NULL
? Could the bit pattern for a NULL void* data-pointer ever equate to a non-NULL function-pointer value? Would any sane implementation do this? Do any common implementations do this?
EDIT: this answer (to a different question admittedly) made me wonder if I had to cast the void* intermediate back to the original function pointer type before I could test NULL-ness, otherwise it's UB... is that true? Can those who posted answers weigh in on this question?
C 2018 6.3.2.3 4 says:
Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
This paragraph, unlike paragraph 7, does not limit the conversions to pointers to object types or pointers to function types. Therefore, if a null pointer of some pointer-to-function type is converted to void *
, the result is a null pointer, and then applying !
to it yields 1.
Establishing the converse, that if applying !
to a pointer yields 1, it necessarily arose from a null pointer, it more difficult. We could imagine some non-null function pointer that, when converted to void *
, yields a null pointer. Considering the intent of POSIX to allow function pointers to be temporarily stored in void *
, we can conclude that converting a pointer to a function to void *
should never result in a null pointer.
Could the bit pattern for a NULL void* data-pointer ever equate to a non-NULL function-pointer value?
The C standard does not discuss the bit patterns used to represent pointers. The semantics are established in terms of the values.
Would any sane implementation do this?
Certainly bare-metal boot code on some hardware might put executable instructions at address zero and call a function there for some reason and might also use address zero as a null pointer. It will simply be designed not to depend on that function at address zero not being tested for being a null pointer.
Outside of such special situations, i.e., for all practical purposes, this is not done. If some software decides it needs a special representation for a null pointer, it will set aside some address for that and not use that address for any ordinary function or object.