¿Por qué no puedo lanzar un puntero de función a (void *)?

¿Por qué no puedo lanzar un puntero de función a (void *)?


Tengo una función que toma una cadena, una matriz de cadenas y una matriz de punteros, busca la cadena en la matriz de cadenas y devuelve el puntero correspondiente de la matriz de punteros. Dado que uso esto para varias cosas diferentes, la matriz de punteros se declara como una matriz de (void *), y la persona que llama debe saber qué tipo de punteros hay realmente (y, por lo tanto, qué tipo de puntero recibe como valor de retorno ).


Sin embargo, cuando paso una serie de punteros de función, recibo una advertencia cuando compilo con -Wpedantic :


sonido metálico:


test.c:40:8: warning: assigning to 'voidfunc' (aka 'void (*)(void)') from 'void *' converts
between void pointer and function pointer [-Wpedantic]

CCG:


test.c:40:8: warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic]
fptr = find_ptr("quux", name_list, (void **)ptr_list,

Aquí hay un archivo de prueba que, a pesar de la advertencia, imprime correctamente "quux":


#include <stdio.h>
#include <string.h>
void foo(void)
{
puts("foo");
}
void bar(void)
{
puts("bar");
}
void quux(void)
{
puts("quux");
}
typedef void (* voidfunc)(void);
voidfunc ptr_list[] = {foo, bar, quux};
char *name_list[] = {"foo", "bar", "quux"};
void *find_ptr(char *name, char *names[], void *ptrs[], int length)
{
int i;
for (i = 0; i < length; i++) {
if (strcmp(name, names[i]) == 0) {
return ptrs[i];
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = find_ptr("quux", name_list, (void **)ptr_list,
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}

¿Hay alguna forma de corregir la advertencia, aparte de no compilar con -Wpedantic? , o duplicando mi función find_ptr, una vez para punteros de función y otra vez para punteros que no son de función? ¿Hay una mejor manera de lograr lo que estoy tratando de hacer?


Respuestas:


No se puede arreglar la advertencia. De hecho, en mi opinión, debería ser un error grave, ya que es ilegal enviar punteros de función a otros punteros porque hoy en día existen arquitecturas en las que esto no es solo una violación del estándar C, sino un error real que hará que el código no trabajo. Los compiladores lo permiten porque muchas arquitecturas se salen con la suya a pesar de que esos programas fallarán gravemente en otras arquitecturas. Pero no es solo una violación estándar teórica, es algo que causa errores reales.


Por ejemplo, en ia64, los punteros de función son (o al menos solían ser la última vez que miré) en realidad dos valores, ambos necesarios para realizar llamadas de función en bibliotecas compartidas o un programa y una biblioteca compartida. Del mismo modo, la práctica común de emitir y llamar punteros de función a funciones que devuelven un valor a un puntero a una función que devuelve un valor nulo porque sabe que ignorará el valor devuelto de todos modos también es ilegal en ia64 porque eso puede provocar que se filtren valores trampa en los registros. causando bloqueos en alguna pieza de código no relacionada muchas instrucciones más tarde.


No emita punteros de función. Siempre pídales que coincidan con los tipos. Esto no es solo pedantería de estándares, es una práctica recomendada importante.