¿Podemos poner una dirección de función de una firma en particular en un puntero de función que se define para tener alguna otra firma y usarla sin problemas?
Por ejemplo, el siguiente código
#include <stdio.h> void print_n(int *pn) { printf("%d\n", *pn); } void print_n_wrapper(void *p) { print_n(p); } int main(void) { int n = 123; void (*f)(void *) = print_n_wrapper; f(&n); f = print_n; f(&n); return 0; }
se compila y funciona bien en mi máquina. ¿Estoy invocando un comportamiento indefinido de alguna manera?
Sí, es un comportamiento indefinido .
Citando C11
, capítulo §6.3.2.3 , Indicadores, ( énfasis mío )
Un puntero a una función de un tipo puede convertirse en un puntero a una función de otro tipo y viceversa; el resultado se comparará igual al puntero original. Si se usa un puntero convertido para llamar a una función cuyo tipo no es compatible con el tipo al que se hace referencia, el comportamiento no está definido.
y con respecto a la parte "función cuyo tipo no es compatible", la definición de compatibilidad es así
Para que dos tipos de funciones sean compatibles, ambos deben especificar tipos de retorno compatibles. (146) Además, las listas de tipos de parámetros, si ambos están presentes, deberán coincidir en el número de parámetros y en el uso del terminador de puntos suspensivos; los parámetros correspondientes tendrán tipos compatibles.
Eso significa que void *
e int *
deberían haber sido del mismo tipo, pero no lo son . Por lo tanto, las funciones tampoco son de tipo compatible.
La llamada a print_n(p)
en print_n_wrapper
está definida ya que todo lo que está haciendo es convertir un void*
que originalmente era un int*
a un int*
La asignación f = print_n;
te dará problemas. Aunque la asignación está definida, el comportamiento en la siguiente llamada f(&n)
no está definido.