Tipo de puntero de función de retorno

8 minutos de lectura

avatar de usuario
SE

A menudo encuentro la necesidad de escribir funciones que devuelvan punteros de función. Siempre que lo hago, el formato básico que uso es:

typedef int (*function_type)(int,int);

function_type getFunc()
{
   function_type test;
   test /* = ...*/;
   return test;
}

Sin embargo, esto puede volverse engorroso cuando se trata de una gran cantidad de funciones, por lo que me gustaría no tener que declarar un typedef para cada una (o para cada clase de funciones)

Puedo eliminar el typedef y declarar la variable local devuelta en la función como:
int (*test)(int a, int b); haciendo que el cuerpo de la función se vea así:

{
     int (*test)(int a, int b);
     test /* = ...*/;
     return test;
}

pero luego no sé qué configurar para el tipo de retorno de la función. Yo he tratado:

int(*)(int,int) getFunc()
{
    int (*test)(int a, int b);
    test /* = ...*/;
    return test;
}

pero eso informa un error de sintaxis. ¿Cómo declaro el tipo de retorno para tal función sin declarar un typedef para el puntero de función? ¿Es posible? También tenga en cuenta que soy consciente de que parece que sería más limpio declarar typedefs, para cada una de las funciones, sin embargo, tengo mucho cuidado de estructurar mi código para que sea lo más limpio y fácil de seguir posible. La razón por la que me gustaría eliminar los typedefs es que a menudo solo se usan para declarar las funciones de recuperación y, por lo tanto, parecen redundantes en el código.

  • +1, interesante, me preguntaba eso hace un tiempo, y solo usé un typedef .

    – esta

    16 de diciembre de 2013 a las 17:36

  • no debería test_type ser function_type? (No es que importe tanto, pero solo para ser completamente claro).

    – Kninnung

    16 de diciembre de 2013 a las 17:37


  • Te estás perdiendo algunas cosas en tu pregunta (por ejemplo, ¿cuál es la definición de test_type). Hace que responder a su pregunta sea mucho más difícil cuando estamos confundidos. jajaja

    – Trozos de violín

    16 de diciembre de 2013 a las 17:37

  • @SE Sí. Estoy tratando de encontrar un buen ejemplo para publicar como respuesta, a menos que creas que ese no es el camino a seguir …

    – Trozos de violín

    16 de diciembre de 2013 a las 17:49

  • @AndyLin Hay muchos. Prácticamente en cualquier momento que tenga que escribir un contenedor de biblioteca. Solo para elegir un ejemplo del mundo real de la parte superior de mi cabeza, suponga que está escribiendo una aplicación opengl y desea admitir la carga dinámica de cualquier versión de opengl que esté en el sistema del usuario. Luego, escribe un contenedor alrededor de open gl y carga dinámicamente cada función gl que usa de la biblioteca. En tales casos, tras la inicialización, desea devolver cada función gl buscando su nombre en esa versión de open gl. De hecho, open gl tiene extensiones que están destinadas a cargarse de esa manera.

    – SE

    13/01/2021 a las 20:55


avatar de usuario
Eric Pospischil

int (*getFunc())(int, int) { … }

Eso proporciona la declaración que solicitó. Además, como señala ola1olsson, sería bueno insertar void:

int (*getFunc(void))(int, int) { … }

esto dice que getFunc puede no tomar ningún parámetro, lo que puede ayudar a evitar errores como que alguien escriba sin darse cuenta getFunc(x, y) en lugar de getFunc()(x, y).

  • Tengo una función miembro de clase y quiero que devuelva un puntero de función. Cómo puedo hacerlo ? no encuentro como. Intenté de esta manera que dices arriba, pero no funcionó.

    – chaviaras michalis

    8 de diciembre de 2017 a las 8:55


  • Buena respuesta. Pero sintaxis de puntero de función C totalmente insensata.

    – Johannes Overman

    23 de febrero de 2018 a las 12:11

  • Sugeriría agregar la palabra clave “void” entre los paréntesis vacíos para que el compilador pueda detectar el error donde la persona que llama a getFunc() podría pensar que le da el argumento int,int a la función real y no a getFunc() . Es decir, desea que el compilador capture “getFunc(x,y)” ya que la persona que llama probablemente quiera hacer “getFunc()(x,y)”.

    – ola1olsson

    5 de marzo de 2018 a las 14:51


  • Puede estar fuera de tema, pero es fácil evaluar la declaración de funciones complejas usando Regla en el sentido de las agujas del reloj/espiral

    – tonyjosi

    26 de febrero de 2020 a las 9:46

avatar de usuario
yosim

Probablemente puedas hacer algo como:

int foo (char i) {return i*2;}

int (*return_foo()) (char c)
{
   return foo;
}

pero Dios, espero nunca tener que depurar tu código…

  • como dije en el problema, no lo usaría en un escenario en el que ensuciara el código. Es solo para esas raras ocasiones en las que declarar muchos de los typedefs es redundante

    – SE

    16 de diciembre de 2013 a las 18:29


  • ¡Vaya! Leer eso de nuevo, fue un poco grosero, lo siento, no quise decir eso, fue una broma.

    – yosim

    16 de diciembre de 2013 a las 19:57

avatar de usuario
Dmitri

dejaré esto aquí ya que fue un poco más complicado que las respuestas ya dadas, ya que requiere un puntero de función

(int (__cdecl *)(const char *))

y devuelve un puntero de función

(int (__cdecl *)(const char *))

#include <stdio.h>

int (*idputs(int (*puts)(const char *)))(const char *) {
    return puts;
}

int main(int argc, char **argv)
{
    idputs(puts)("Hey!");

    return 0;
}

Mientras envolvía un código C en clases de C++, tenía el mismo deseo que el póster original: devolver un puntero de función desde una función sin recurrir a typedef‘ing el prototipo de puntero de función. Tengo un problema con C++ const corrección que pensé que valía la pena compartir, incluso si está un poco fuera de tema (C ++), pero se relaciona directamente con la pregunta original: la sintaxis para devolver un puntero de función C sin recurrir a un typedef.

El siguiente código define una clase. A que almacena un puntero de función y lo expone al mundo exterior a través del get_f() llamada. Esta es la función que debería devolver un puntero de función sin un typedef.

El punto (que me desconcertó durante algún tiempo) era cómo declarar que get_f() era un const función, es decir, no alteraría A.

El código contiene 2 variantes: la primera usa un typedef para el prototipo del puntero de función, mientras que la segunda escribe todo en su totalidad. los #if cambia entre los dos.

#include <iostream>

int my_f(int i)
{
  return i + 1;
}

#if 0 // The version using a typedef'ed function pointer

typedef int (*func_t)(int);

class A
{
public:
  A(func_t f) : m_f(f) {}
  func_t get_f() const { return m_f; }

private:
  func_t m_f;
};

int main(int argc, char *argv[])
{
  const A a(my_f);
  std::cout << "result = " << a.get_f()(2) << std::endl;
}

#else // The version using explicitly prototyped function pointer    

class A
{
public:
  A(int (*f)(int)) : m_f(f) {}
  int (*get_f() const)(int) { return m_f; }

private:
  int (*m_f)(int);
};

int main(int argc, char *argv[])
{
  const A a(my_f);
  std::cout << "result = " << a.get_f()(2) << std::endl;
}

#endif

El resultado esperado/deseado es:

result = 3

El punto clave es la posición del const calificador en la línea:

int (*get_f() const)(int) { return m_f; }

Este es un ejemplo estúpido, pero es simple y no da errores. Se trata solo de declarar funciones estáticas:

#include <stdio.h>
#include <stdlib.h>

void * asdf(int);
static int * hjkl(char,float);

main() {
  int a = 0;
  asdf(a);
 }


void * asdf(int a) {return (void *)hjkl; }
static int * hjkl(char a, float b) {int * c; return c;}

  • El estándar C no define el comportamiento de convertir punteros a datos en punteros a función. Además, esto no es más simple que el ejemplo del OP.

    – Andrei Mishchenko

    16 de diciembre de 2013 a las 17:58

  • en realidad, no está lanzando un puntero a datos a un puntero a una función. Tiene un apuntador a una función, y lo está lanzando a un vacío* y luego lo está devolviendo a una función. esto es válido, y de hecho void* tipos de retorno es cómo funciona la función dlsym de GNU, el problema es que es básicamente una forma de escritura débil que trato de evitar

    – SE

    29/09/2014 a las 18:29

avatar de usuario
Rafael Rossi

Creo que tienes tres opciones:

  1. Quédese con typedef. Al final del día, es trabajo de typedef.
  2. Vuelve vacío* y el vaciado.
  3. Reconsidere su arquitectura de software. Tal vez podría compartir con nosotros lo que está tratando de lograr y ver si podemos orientarlo hacia una mejor dirección.

  • El estándar C no define el comportamiento de convertir punteros a datos en punteros a función. Además, esto no es más simple que el ejemplo del OP.

    – Andrei Mishchenko

    16 de diciembre de 2013 a las 17:58

  • en realidad, no está lanzando un puntero a datos a un puntero a una función. Tiene un apuntador a una función, y lo está lanzando a un vacío* y luego lo está devolviendo a una función. esto es válido, y de hecho void* tipos de retorno es cómo funciona la función dlsym de GNU, el problema es que es básicamente una forma de escritura débil que trato de evitar

    – SE

    29/09/2014 a las 18:29

avatar de usuario
Jia Hao Xu

Puede escribir el siguiente código (solo funciona en C++ 11 y superior):

//C++11
auto func(...) {
    int (*fptr)(...) ret = ...
    //Do sth.
    return ret;//C++11 compiler will automatically deduce the return type for you
}

O, si no le gusta la deducción automática del tipo de devolución, puede especificar el tipo al final de la función (igual que arriba, solo en C++ 11 y superior):

//C++11
auto func(...) -> int (*)(...) { /* Do sth. */ }

  • gracias por la respuesta, pero la pregunta era sobre c no c++.

    – SE

    9 de abril de 2018 a las 13:14

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad