Definir una función que devuelve un puntero de función que también devuelve un puntero de función sin typedefs
function function-pointers (4)
Estoy tratando de entender realmente los punteros de función sin usar
typedef
pero parece que no puedo entender esto.
No entiendo qué firma se necesita para transmitir que devuelvo un puntero a un puntero a una función.
#include <stdio.h>
void odd() { printf("odd!/n"); }
void even() { printf("even!/n"); }
void (*get_pfn(int i))()
{
return i % 2 == 0 ? &even : &odd;
}
__SIGNATURE__
{
return &get_pfn;
}
int main()
{
get_pfn_pfn()(1)();
get_pfn_pfn()(2)();
return 0;
}
Para que esto funcione, ¿
__SIGNATURE__
tiene que ser
__SIGNATURE__
?
El tipo de retorno de la función
get_pfn
es -
void (*) ();
Entonces, el tipo de
&get_pfn
es -
void (*(*)(int))()
Ahora, esta función devuelve este tipo, por lo tanto, su firma será:
void (*(*(foo)())(int))()
Puede verificar esto escribiendo esto en cdecl.org
Los punteros de función sin
typedef
pueden ser difíciles de trabajar.
Para resolverlos, trabajas de adentro hacia afuera.
Analicemos exactamente cómo encontramos la firma de función correcta.
get_pfn_pfn
es una función:
get_pfn_pfn()
Que no tiene parámetros:
get_pfn_pfn(void)
Y devuelve un puntero:
*get_pfn_pfn(void)
A una función:
(*get_pfn_pfn(void))()
Que toma un parámetro
int
:
(*get_pfn_pfn(void))(int)
Y devuelve un puntero:
*(*get_pfn_pfn(void))(int)
A una función:
(*(*get_pfn_pfn(void))(int))()
Que no tiene parámetros:
(*(*get_pfn_pfn(void))(int))(void)
Y no devuelve nada (es decir,
void
):
void (*(*get_pfn_pfn(void))(int))(void)
Por supuesto, usar
typedef
''s simplifica esto enormemente.
Primero el tipo para
even
e
odd
:
typedef void (*func1)(void);
Lo que luego podemos aplicar a
get_pfn
:
func1 get_pfn(int) { ... }
Entonces el tipo para esta función:
typedef func1 (*func2)(int);
Lo que podemos aplicar a
get_pfn_pfn
:
func2 get_pfn_pfn(void) { ... }
Tiene que devolver un puntero de función a una función que toma un
int
y devuelve un puntero de función:
void (*(*get_pfn_pfn(void))(int))(void) {
return &get_pfn;
}
mas lineas:
void (*
(*
get_pfn_pfn(void) // this is our function
)(int i) // this is get_pfn(int)
)(void) // this is odd() or even()
{
return &get_pfn;
}
Se pueden omitir los
void
, en cuyo caso el puntero de función apunta a una función que toma un número desconocido de parámetros.
Que no es lo que quieres.
Para declarar un puntero de función a una función que no toma argumentos, debe agregar
void
dentro de la lista de parámetros de función.
De la misma manera, es mejor cambiar
get_pfn
a
void (*get_pfn(int i))(void)
.
Por ejemplo, intente llamar desde
get_pfn(1)("some arg", "some other arg");
.
El compilador de CA no dará una advertencia, ya que empty
()
denota argumentos
desconocidos
.
Para decir que la función no requiere argumentos, debe
(void)
.
Para muchas secuencias de llaves, especialmente
))(
en punteros de función son difíciles de analizar. Por eso muchos prefieren typedefs para punteros de función o tipos:
typedef void get_pfn_func_t(void);
get_pfn_func_t *get_pfn(int i) {
return i % 2 == 0 ? &even : &odd;
}
typedef get_pfn_func_t *get_pfn_pfn_func_t(int i);
get_pfn_pfn_func_t *get_pfn_pfn(void) {
return &get_pfn;
}
es por aquí:
void (*(*get_pfn_pfn(void))(int))()