POSIX requiere (creo) que los punteros de función se puedan almacenar en una variable de tipo void* y/o pasar a funciones que esperan un argumento void*, aunque esto no es estrictamente estándar.
Mi pregunta es esta: si pruebo tal variable/argumento para NULL -ness, if (!(variable or argument)) diga, y el resultado es true , ¿significa eso necesariamente que el puntero de función es NULL ? ¿Podría el patrón de bits para un puntero de datos NULL void* igualar alguna vez a un valor de puntero de función no NULL? ¿Alguna implementación sensata haría esto? ¿Alguna implementación común hace esto?
EDITAR: esta respuesta (a una pregunta diferente ciertamente) me hizo preguntarme si tenía que devolver el intermedio void * al tipo de puntero de función original antes de poder probar NULL-ness, de lo contrario es UB ... ¿es eso cierto? ¿Pueden los que publicaron respuestas opinar sobre esta pregunta?
C 2018 6.3.2.3 4 dice:
La conversión de un puntero nulo a otro tipo de puntero produce un puntero nulo de ese tipo. Cualquier dos punteros nulos se compararán iguales.
Este párrafo, a diferencia del párrafo 7, no limita las conversiones a punteros a tipos de objetos o punteros a tipos de funciones. Por lo tanto, si un puntero nulo de algún tipo de puntero a función se convierte en void * , el resultado es un puntero nulo, y luego aplicar ! le da 1.
Estableciendo lo contrario, que si aplica ! a un puntero da 1, necesariamente surgió de un puntero nulo, más difícil. Podríamos imaginar algún puntero de función no nulo que, cuando se convierte en void * , produce un puntero nulo. Teniendo en cuenta la intención de POSIX de permitir que los punteros de función se almacenen temporalmente en void * , podemos concluir que convertir un puntero en una función para void * nunca debería dar como resultado un puntero nulo.
¿Podría el patrón de bits para un puntero de datos NULL void* igualar alguna vez a un valor de puntero de función no NULL?
El estándar C no analiza los patrones de bits utilizados para representar punteros. La semántica se establece en función de los valores.
¿Alguna implementación sensata haría esto?
Ciertamente, el código de arranque completo en algún hardware podría poner instrucciones ejecutables en la dirección cero y llamar a una función allí por alguna razón y también podría usar la dirección cero como un puntero nulo. Simplemente se diseñará para no depender de que la función en la dirección cero no se pruebe como un puntero nulo.
Fuera de tales situaciones especiales, es decir, para todos los efectos prácticos, esto no se hace. Si algún software decide que necesita una representación especial para un puntero nulo, reservará una dirección para eso y no usará esa dirección para ninguna función u objeto ordinario.
Este borrador de estándar C11 sugiere que, si bien no forma parte del estándar central , la conversión de punteros de función a punteros de objeto (para fines de prueba, como en su verificación NULL ) se incluye en la categoría de "Extensiones comunes" (Anexo J.5):
J.5.7 Conversiones de puntero de función
1 Un puntero a un objeto oa
voidpuede convertirse en un puntero a una función, lo que permite invocar datos como una función (6.5.4).2 Un puntero a una función puede convertirse en un puntero a un objeto o a
void, lo que permite inspeccionar o modificar una función (por ejemplo, mediante un depurador) (6.5.4)
Si una implementación tuviera como objetivo una plataforma donde el patrón de bits idiomático común para un puntero de código nulo fuera diferente del patrón de bits idiomático común para un puntero de datos nulo, sería libre de exponer el hecho de que los punteros son diferentes para el programador , o envuelva las operaciones de puntero en una abstracción que haría que se comportaran de manera idéntica. Los autores del estándar no intentaron adivinar qué enfoque sería más útil, ya que las personas que realmente estaban escribiendo código para la plataforma en cuestión estarían en mejores condiciones que el Comité para juzgar los pros y los contras de cada enfoque.
En la situación mucho más común en la que una plataforma de destino usa la misma representación para ambos tipos de punteros nulos, los autores del estándar habrían esperado que las implementaciones almacenaran ambos tipos de punteros de esa manera, pero también habrían considerado la idea de que tal las implementaciones deberían comportarse de esa manera como lo suficientemente obvio como para que no haya necesidad de gastar tinta recomendando tal comportamiento.
El hecho de que el Estándar no ordene el comportamiento común no implica ningún juicio de que las implementaciones deban hacer otra cosa, sino simplemente un reconocimiento de que pueden existir implementaciones donde algún otro comportamiento a veces puede ser más útil que el común.