Puntero vacío C para puntero a la función

Estoy intentando crear algunas macros que puedo usar para crear mi propia biblioteca de pruebas unitarias. Mi archivo de encabezado se ve así:

#ifndef _TEST_H_ #define _TEST_H_ #include  #include "hehe_stack.h" static hehe_stack* tests; typedef int (*testfunc)(); #define test_init() tests = hehe_stack_init(); #define test_register(test) hehe_stack_push(tests, test); #define test_info() fprintf(stdout, "running %s :: %s \n", __FILE__, __func__); #define test_run() testfunc = (int (*)()) hehe_stack_pop(tests); testfunc(); return 0; #endif 

En cada archivo .c de prueba, deseo insertar un número de punteros de función en la stack de pruebas y luego sacar cada puntero de función de la stack y llamarla. El método My stack pop devuelve un puntero void, y el puntero de función que estoy presionando sobre él devuelve un int y no toma ningún parámetro. ¿Mi syntax es incorrecta? Siento que debería ser capaz de hacer esto.

El estándar C99 no permite convertir punteros a datos (en el estándar, “objetos o tipos incompletos”, por ejemplo, char* o void* ) y punteros a funciones.

6.3.2.3:8 Un puntero a una función de un tipo se puede convertir en un puntero a una función de otro tipo y viceversa; el resultado se comparará igual al puntero original. Si un puntero convertido se usa para llamar a una función cuyo tipo no es compatible con el tipo apuntado, el comportamiento no está definido.

Una razón es que los punteros a objetos y punteros a funciones no tienen que ser del mismo tamaño. En una architecture de ejemplo, la primera puede ser de 64 bits y la última de 32 bits.

Puede convertir desde un puntero a un tipo de función determinado a un puntero a otro tipo de función, y esta es la técnica que recomiendo que use si necesita almacenar punteros de función en una estructura de datos. Cualquier tipo de función hará. Esto significa que no puede reutilizar una estructura de datos destinada a punteros de datos. Necesita duplicar la estructura de datos y cambiarla para que contenga punteros a funciones.

No olvide devolver el tipo de puntero a la función adecuada antes de llamar, de lo contrario, este es un comportamiento indefinido.

TEN EN CUENTA que, como señaló Andrew Mellinger, algunos comstackdores permiten la conversión en cada dirección. Las listas del anexo “J.5 Extensiones comunes” de C11:

J.5.7 Moldes de puntero de función

1 Un puntero a un objeto o a un vacío se puede convertir en un puntero a una función, permitiendo que los datos se invoquen como una función (6.5.4).

2 Un puntero a una función se puede convertir a un puntero a un objeto o anular, permitiendo que una función sea inspeccionada o modificada (por ejemplo, por un depurador) (6.5.4).

Algunas interfaces POSIX, como dlsym() , también dlsym() estas conversiones a ser válidas en el comstackdor C del sistema POSIX.

Puedes hacerlo, pero se supone que no debes hacerlo por accidente, por lo que la syntax es especialmente incómoda. Uno no lanza el puntero a la función, sino un puntero a un puntero a la función, y luego lo asigna.

 #define test_run() *((void**)&testfunc) = hehe_stack_pop(tests); testfunc(); return 0; 

Esto convierte &testfunc en un puntero a un void* , luego lo desreferencia y le asigna el valor de otro void* , que es legal.

El código sugerido nunca se comstack ya que no se supone que debes eliminar la referencia de un puntero void * (¿cómo podrías?) No hay información de tipo sobre el puntero en particular).

La manera correcta de hacer esto sugiere cmotley en su comentario, aunque recomendaría una pequeña mejora en aras de la legibilidad:

 typedef int (*tTestFuncSignature)(void) #define test_run() tTestFuncSignature testfunc = hehe_stack_pop(tests); testfunc(); 

o incluso para evitar enfrentamientos de nombres ocultos usando esta macro:

 #define test_run() ((tTestFuncSignature)hehe_stack_pop(tests))(); 

De cualquier manera, debes asegurarte (por ejemplo, por contrato) de que solo tienes punteros válidos en tu stack o prueba primero el puntero antes de invocar la función.

Editar: formateo de código corregido