El nombre de la función debe ser un reflejo de la función. La mayoría de las personas que aprenden C cubren qsort tarde o temprano, ¿qué hace exactamente esto?
mckenzm
55
@MooingDuck No estoy de acuerdo con su sugerencia, y su sugerencia carece de razonamiento para apoyar la conclusión. Personalmente prefiero nunca usar typedef en los punteros de función, y creo que hace que el código sea más claro y fácil de leer.
andrewrk
2
@andrewrk: ¿Prefieres void funcA(void(*funcB)(int))y void (*funcA())()a typedef void funcB(); void funcA(funcB)y funcB funcA()? No veo lo bueno.
Mooing Duck
Respuestas:
747
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 fserá un puntero a una función que tiene un voidtipo de retorno y que toma un solo intparámetro. La siguiente función ( print) es un ejemplo de una función a la que podría pasarse funccomo 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, funcahora puede usar el nombre del parámetro en el cuerpo de la función para acceder al valor del parámetro. Digamos que funcaplicará 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 funcla declaración de parámetros dice que ese fes el nombre de un puntero a la función deseada, recordamos primero que si fes un puntero, entonces *fes lo que fapunta (es decir, la función printen este caso). Como resultado, simplemente reemplace cada aparición de impresión en el bucle anterior con *f:
En su primer y último ejemplo de código, el * no es obligatorio. Tanto la definición del parámetro de la ffunción como la llamada a la función pueden tomarse ftal 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.
Gauthier
55
Ver [c99, 6.9.1§14] para ejemplos. Ambos son correctos, por supuesto, solo quería mencionar la alternativa.
Gauthier
66
De Verdad? ¿La respuesta mejor calificada no hace una sola referencia al uso typedefde los punteros de función for? Lo siento, tengo que votar abajo.
Jonathon Reinhart
3
@JonathonReinhart, ¿cuáles serían las ventajas de la aplicación 'typedef'? Sin embargo, esta versión se ve mucho más limpia y carece de declaraciones adicionales. más o menos entrante aquí.
Abhinav Gauniyal
3
@JonathonReinhart bien visto; Debe notarse explícitamente que los punteros typedefs ofuscan el código y, por lo tanto, no deben usarse.
MM
128
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.
typedefvoid(*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:
Para una función que devuelve un int y toma un char que haría
typedefint(*functiontype2)(char);
y para usarlo
int dosomethingwithchar(char a){return1;}
functiontype2 func2 =&dosomethingwithcharint 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!
Si desea "convertir un puntero de función en un tipo", no necesita la biblioteca de impulso. Solo usa typedef; Es más simple y no requiere ninguna biblioteca adicional.
wizzwizz4
73
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 booles 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:
Quizás la pregunta para C ++ no debería mencionarse aquí porque esta pregunta es C.
Michael Fulton
55
Esta pregunta surgió primero cuando busqué "llamada a función c ++ como parámetro", por lo que esta respuesta está cumpliendo su propósito aquí independientemente.
ufoxDan
25
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 printreturn0;}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 printreturn0;}void print(){
printf("Hello!");}void execute(void(*f)())// receive address of print{
f();}
Muy buena respuesta, con bloques enteros de código (en lugar de cortar todo en un lío incomprensible). ¿Podría explicar las diferencias de ambas técnicas?
Rafael Eyng
5
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:
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>intIncMultInt(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;}));return0;}
typedef
.void funcA(void(*funcB)(int))
yvoid (*funcA())()
atypedef void funcB(); void funcA(funcB)
yfuncB funcA()
? No veo lo bueno.Respuestas:
Declaración
Un prototipo para una función que toma un parámetro de función tiene el siguiente aspecto:
Esto indica que el parámetro
f
será un puntero a una función que tiene unvoid
tipo de retorno y que toma un soloint
parámetro. La siguiente función (print
) es un ejemplo de una función a la que podría pasarsefunc
como parámetro porque es del tipo adecuado: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:
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 quefunc
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:Dado que
func
la declaración de parámetros dice que esef
es el nombre de un puntero a la función deseada, recordamos primero que sif
es un puntero, entonces*f
es lo quef
apunta (es decir, la funciónprint
en este caso). Como resultado, simplemente reemplace cada aparición de impresión en el bucle anterior con*f
:Fuente
fuente
f
función como la llamada a la función pueden tomarsef
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.
Declara una función que devuelve void y no toma argumentos. Para crear un puntero de función para este tipo ahora puede hacer:
Para una función que devuelve un int y toma un char que haría
y para usarlo
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!
es mucho mejor que lo anterior.
fuente
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,
donde
bool
es el tipo de retorno aquí de una función de un argumento cuyo primer argumento es de tipoint
.He incluido un programa de ejemplo a continuación:
Sin embargo, a veces es más conveniente usar una función de plantilla:
fuente
Pase la dirección de una función como parámetro a otra función como se muestra a continuación
También podemos pasar la función como parámetro usando el puntero de función
fuente
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:
es equivalente a esto:
fuente
Necesita pasar un puntero de función . La sintaxis es un poco engorrosa, pero es realmente poderosa una vez que te familiarizas con ella.
fuente
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.
fuente
IncMultInt
?