Funciones dentro de funciones en C [duplicate]

7 minutos de lectura

avatar de usuario
Rafael S. Calsaverini

Estoy haciendo un código que es similar a este:

#include <stdio.h>

double some_function( double x, double y)
{
  double inner_function(double x)
  { 
    // some code
    return x*x;
  }

  double z;
  z = inner_function(x);
  return z+y;

}

int main(void)
{
  printf("%f\n", some_function(2.0, 4.0));
  return 0;
}

Esto compila perfectamente en GCC (sin advertencias) pero falla al compilar en ICC.

ICC da:

main.c(16): error: expected a ";"
    { 
    ^

main.c(21): warning #12: parsing restarts here after previous syntax error
    double z;
            ^

main.c(22): error: identifier "z" is undefined
    z = inner_function(x);
    ^

compilation aborted for main.c (code 2)

¿Qué estoy haciendo mal?

Gracias.

(editar) Perdón por el mal ejemplo. En mi código original, necesito hacer estas cosas. Estoy usando un integrador numérico GSL y tengo algo como:

double stuff(double a, double b)
{
  struct parameters
  {
    double a, b;
  };

  double f(double x, void * params)
  {
    struct parameters p = (struct parameters *) params;
    double a = p->a, b = b->b;
    return some_expression_involving(a,b,x);
  }
  struct parameters par = {a,b};

  integrate(&f, &par);

}

Y tengo muchas funciones con este tipo de estructura: son el resultado de una integración de funciones con muchos parámetros externos. Y las funciones que implementan integración numérica deben recibir un puntero a una función de tipo:

double f(double x, void * par)

Realmente me gustaría que las funciones se aniden de esta manera para que mi código no se llene de muchas funciones. Y espero poder compilarlo con ICC para acelerar un poco las cosas.

  • Ustedes rocas!! ¡En menos de 2 minutos tenía respuestas completas!

    – Rafael S. Calsaverini

    5 de junio de 2009 a las 19:32

  • Yo amigo, te escucho como funciones…

    – GreenieMeanie

    5 de junio de 2009 a las 20:06

  • Es por eso que necesito expresiones lambda en C. 🙁

    – Rafael S. Calsaverini

    29 de diciembre de 2009 a las 1:08

  • Con respecto a, “No veo por qué realmente necesita funciones anidadas en absoluto”, la razón por la que más personas se están moviendo hacia este estilo de desarrollo es moverse hacia los mecanismos de espacio de nombres y alcance de JavaScript. Una función encapsula otras funciones y expone funciones a través de una estructura. Aún tengo que ver si esto simplifica el desarrollo o el uso futuro de la biblioteca.

    – Arco E Net

    8 de agosto de 2016 a las 0:29

avatar de usuario
joshdick

Las funciones anidadas están disponibles como extensión de idioma en GCCpero no forman parte del lenguaje estándar, por lo que algunos compiladores no los permitirán.

  • +1: una nota rápida para el OP: creo que está recibiendo el error en GCC a pesar de que admite funciones anidadas porque ha escrito mal el nombre de la función. función_interna() debe ser función_interna().

    – Michael Burr

    5 de junio de 2009 a las 19:21

  • Veo. Gracias por la respuesta MUY rápida. Estaba usando esto sin darme cuenta de que no era estándar. Eso es muy malo. Veo que mi código será muy difícil de entender si sigo usando icc.

    – Rafael S. Calsaverini

    5 de junio de 2009 a las 19:27

  • La última vez que pasé de JavaScript a C, intenté usar funciones anidadas. Me encantan las funciones anidadas. Pero no renuncie a hacer que su C sea fácil de leer, comprender y depurar. Es factible.

    – Nosredna

    5 de junio de 2009 a las 19:56

Todos los demás le han dado la respuesta canónica “Las funciones anidadas no están permitidas en C estándar” (por lo que cualquier uso de ellas depende de su compilador).

Su ejemplo revisado es:

double stuff(double a, double b)
{
  struct parameters
  {
    double a, b;
  };

  double f(double x, void * params)
  {
    struct parameters p = (struct parameters *) params;
    double a = p->a, b = b->b;
    return some_expression_involving(a,b,x);
  }
  struct parameters par = {a,b};

  return integrate(&f, &par);     // return added!
}

Como dices que las funciones como el integrador necesitan

  double (*f)(double x, void * par);

No veo por qué realmente necesitas funciones anidadas. Yo esperaría escribir:

struct parameters
{
    double a, b;
};

static double f(double x, void *params)
{
    struct parameters p = (struct parameters *) params;
    double a = p->a, b = b->b;
    return some_expression_involving(a,b,x);
}

double stuff(double a, double b)
{
    struct parameters par = { a, b };
    return integrate(f, &par);
}

El código anterior debería funcionar en C89 (a menos que haya un problema con la inicialización de ‘par’ de esa manera) o C99; esta versión del código es solo para C99, usando un literal compuesto para el parámetro (sección 6.5.2.5 Literales compuestos):

double stuff(double a, double b)
{
    return integrate(f, &(struct parameters){a, b});
}

Las posibilidades son excelentes de que solo tenga unas pocas variaciones en el tipo de ‘parámetros de estructura’. Debe proporcionar nombres separados (suficientemente) significativos para las diversas funciones: solo puede tener una función llamada ‘f‘ por archivo fuente.

El único beneficio marginal y diminuto de la versión de función anidada es que puede estar seguro de que ninguna otra función que no sea stuff llamadas f. Pero dado el código de ejemplo, eso no es un gran beneficio; la definición estática de f significa que ninguna función fuera de este archivo puede llamarlo a menos que se pase un puntero a la función.

  • Hola Jonathan, mi razón para usar funciones anidadas fue que, dado que f no es un usuario en ninguna parte excepto para calcular la integral, pensé que esta era una buena manera de hacer que el código fuera más legible para mí. Pero tal vez no. Tengo muchas funciones para integrar (en realidad es una solución de un sistema de ecuaciones acopladas en el que cada ecuación es una integral) Pensé que dejar las funciones que se usan solo una vez flotando en el código era una mala práctica. Si pudiera usar funciones lambda como en python o Haskell, sería genial. Pero necesito velocidad para este problema y no conozco suficiente Haskell.

    – Rafael S. Calsaverini

    8 de junio de 2009 a las 0:40

avatar de usuario
Nosredna

C no tiene funciones anidadas. Las funciones anidadas de GCC son una extensión del lenguaje.

Su error de tiempo de ejecución en GCC es un error de ortografía. inner_funcion debiera ser inner_function.

  • Oh, Ups. Gracias, corregí el nombre de la función.

    – Rafael S. Calsaverini

    5 de junio de 2009 a las 19:22

  • ¿Por qué demonios agregaron una extensión tan no estándar a C? ¿Hay un interruptor del compilador para apagarlo?

    – jmucchiello

    6 de junio de 2009 a las 1:05

  • No estoy seguro. Probablemente. Recuerdo que tuve la opción de habilitarlos en XCode cuando comencé a desarrollar iPhone. Decidí no habilitar. Me encantan las funciones anidadas, pero para mí una de las grandes ventajas de la C pura es la portabilidad.

    – Nosredna

    6 de junio de 2009 a las 1:23

  • Consulte mi respuesta para obtener una explicación de cómo escribir código portátil ISO C90.

    – Nick Presta

    6 de junio de 2009 a las 4:04

  • @Nick Presta: gracias por los consejos.

    – Nosredna

    6 de junio de 2009 a las 5:03

avatar de usuario
dan olson

Como se mencionó en muchas respuestas anteriores, las funciones internas no son compatibles con C, sin embargo, las funciones internas clases se puede usar en C++ para lograr algo similar. Desafortunadamente, son un poco difíciles de usar, pero podría ser una opción para ti si no te importa compilar como C++.

Ejemplo no probado:

double some_function( double x, double y)
{
  struct InnerFuncs
  {
    double inner_function(double x)
    { 
      // some code
      return x*x;
    }
    // put more functions here if you wish...
  } inner;

  double z;
  z = inner.inner_function(x);
  return z+y; 
}

Tenga en cuenta que esta respuesta no debería implicar que creo que las funciones internas son una buena idea en el uso que ha mostrado.

Edición de años después:

C++ ahora nos permite usar lambdas como funciones internas. En el caso de mi ejemplo de juguete anterior, se parecería mucho a esto:

double some_function( double x, double y)
{
   auto inner_function = [&]() { return x * x; }

   double z;
   z = inner_function ();
   return z + y;
}

Tenga en cuenta que la variable local x se captura automáticamente dentro de la lambda, lo cual es una característica muy buena.

Más aquí: ¿Qué es una expresión lambda en C++ 11?

Está utilizando funciones anidadas: C no admite tales cosas.

avatar de usuario
naveen

Ese no es un código C válido, las funciones internas no son compatibles con C

avatar de usuario
aJ.

las definiciones de funciones locales dentro de una función son ilegales en C.

¿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