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 para una función que toma un parámetro de función tiene el siguiente aspecto:
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 solo int
parámetro. La siguiente función ( print
) es un ejemplo de una función a la que podría pasarse 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. Use 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 la 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. Considere, primero, cómo sería el ciclo para llamar a print directamente:
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
print(ctr);
}
Dado que func
la declaración de parámetros dice que ese f
es el nombre de un puntero a la función deseada, recordamos primero que si 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 impresión en el bucle anterior con *f
:
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
f
función como la llamada a la función pueden tomarse f
tal como están sin *. Sin embargo, puede ser una buena idea hacerlo como lo hace, para que sea obvio que el parámetro f es un puntero de función. Pero daña la legibilidad con bastante frecuencia.
typedef
de los punteros de función for? Lo siento, tengo que votar abajo.
Esta pregunta ya tiene la respuesta para definir punteros de función, sin embargo, pueden volverse muy complicados, especialmente si los va a pasar por su aplicación. Para evitar esta molestia, le recomendaría que escriba el puntero de la función en algo más legible. Por ejemplo.
typedef void (*functiontype)();
Declara una función que devuelve void y no toma 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 char que haría
typedef int (*functiontype2)(char);
y para usarlo
int dosomethingwithchar(char a) { return 1; }
functiontype2 func2 = &dosomethingwithchar
int result = func2('a');
Hay 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 lo anterior.
typedef
; Es más simple y no requiere ninguna biblioteca adicional.
Desde C ++ 11 puede usar la biblioteca funcional para hacer esto de manera sucinta y genérica. La sintaxis es, por ejemplo,
std::function<bool (int)>
donde bool
es el tipo de retorno aquí 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);
}
Sin embargo, a veces es más conveniente usar 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 '' puntero 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));
Necesita pasar un puntero de función . La sintaxis es un poco engorrosa, pero es realmente poderosa una vez que te familiarizas con ella.
No es realmente una función, pero es un código localizado. Por supuesto, no pasa el código solo el resultado. No funcionará si se pasa a un despachador de eventos para que se ejecute más adelante (ya que el resultado se calcula ahora y no cuando se produce el evento). Pero sí localiza su código en un solo lugar si eso es todo lo que está tratando de hacer.
#include <stdio.h>
int IncMultInt(int a, int b)
{
a++;
return a * b;
}
int main(int argc, char *argv[])
{
int a = 5;
int b = 7;
printf("%d * %d = %d\n", a, b, IncMultInt(a, b));
b = 9;
// Create some local code with it's own local variable
printf("%d * %d = %d\n", a, b, ( { int _a = a+1; _a * b; } ) );
return 0;
}
IncMultInt
?
typedef
.void funcA(void(*funcB)(int))
yvoid (*funcA())()
atypedef void funcB(); void funcA(funcB)
yfuncB funcA()
? No veo lo bueno.