¿Cómo se pasa una función como parámetro en C?
Quiero crear una función que realice una función pasada por parámetro en un conjunto de datos. ¿Cómo se pasa una función como parámetro en C?
Declaración
Un prototipo de una función que toma un parámetro de función se parece al siguiente:
void func ( void (*f)(int) );
Esto indica que el parámetro f
será un puntero a una función que tiene un void
tipo de retorno y que toma un único int
parámetro. La siguiente función ( print
) es un ejemplo de una función a la que se podría pasar func
como parámetro porque es del tipo adecuado:
void print ( int x ) {
printf("%d\n", x);
}
Llamada de función
Al llamar a una función con un parámetro de función, el valor pasado debe ser un puntero a una función. Utilice el nombre de la función (sin paréntesis) para esto:
func(print);
llamaría func
, pasándole la función de impresión.
Cuerpo de función
Al igual que con cualquier parámetro, func
ahora puede usar el nombre del parámetro en el cuerpo de la función para acceder al valor del parámetro. Digamos que func
aplicará la función que se pasa a los números 0-4. Consideremos, primero, cómo se vería el bucle al llamar a imprimir directamente:
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
print(ctr);
}
Dado que func
la declaración del parámetro de 's dice que f
es el nombre de un puntero a la función deseada, primero recordamos que if f
es un puntero, entonces *f
es lo que f
apunta (es decir, la función print
en este caso). Como resultado, simplemente reemplace cada aparición de print en el bucle anterior con *f
:
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
Fuente
Esta pregunta ya tiene la respuesta para definir punteros de función, sin embargo, pueden resultar muy complicados, especialmente si los va a pasar por su aplicación. Para evitar este malestar, recomendaría que escribadef el puntero de función en algo más legible. Por ejemplo.
typedef void (*functiontype)();
Declara una función que devuelve nula y no acepta argumentos. Para crear un puntero de función para este tipo, ahora puede hacer:
void dosomething() { }
functiontype func = &dosomething;
func();
Para una función que devuelve un int y toma un carácter, lo harías
typedef int (*functiontype2)(char);
y para usarlo
int dosomethingwithchar(char a) { return 1; }
functiontype2 func2 = &dosomethingwithchar
int result = func2('a');
Existen bibliotecas que pueden ayudar a convertir los punteros de función en tipos agradables y legibles. ¡ La biblioteca de funciones de impulso es excelente y vale la pena el esfuerzo!
boost::function<int (char a)> functiontype2;
es mucho mejor que el anterior.
Desde C++ 11, puede utilizar la biblioteca funcional para hacer esto de forma concisa y genérica. La sintaxis es, por ejemplo,
std::function<bool (int)>
¿Dónde bool
está aquí el tipo de retorno de una función de un argumento cuyo primer argumento es de tipo int
?
He incluido un programa de ejemplo a continuación:
// g++ test.cpp --std=c++11
#include <functional>
double Combiner(double a, double b, std::function<double (double,double)> func){
return func(a,b);
}
double Add(double a, double b){
return a+b;
}
double Mult(double a, double b){
return a*b;
}
int main(){
Combiner(12,13,Add);
Combiner(12,13,Mult);
}
A veces, sin embargo, es más conveniente utilizar una función de plantilla:
// g++ test.cpp --std=c++11
template<class T>
double Combiner(double a, double b, T func){
return func(a,b);
}
double Add(double a, double b){
return a+b;
}
double Mult(double a, double b){
return a*b;
}
int main(){
Combiner(12,13,Add);
Combiner(12,13,Mult);
}
Pase la dirección de una función como parámetro a otra función como se muestra a continuación
#include <stdio.h>
void print();
void execute(void());
int main()
{
execute(print); // sends address of print
return 0;
}
void print()
{
printf("Hello!");
}
void execute(void f()) // receive address of print
{
f();
}
También podemos pasar la función como parámetro usando el puntero de función.
#include <stdio.h>
void print();
void execute(void (*f)());
int main()
{
execute(&print); // sends address of print
return 0;
}
void print()
{
printf("Hello!");
}
void execute(void (*f)()) // receive address of print
{
f();
}
Las funciones se pueden "pasar" como punteros de función, según ISO C11 6.7.6.3p8: " Una declaración de un parámetro como ''tipo de retorno de función'' se ajustará a ''tipo de retorno de función'' , como en 6.3 .2.1." Por ejemplo, esto:
void foo(int bar(int, int));
es equivalente a esto:
void foo(int (*bar)(int, int));