2009-06-05 57 views
26

estoy haciendo un código que es similar al siguiente:funciones dentro de las funciones en C

#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 el ICC.

CPI 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.

(corregir) Perdón por el pobre ejemplo. En mi código original, necesito hacer esto. Estoy usando un integrador numérico GSL y tener 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 un montón de funciones con este tipo de estructura: son el resultado de una integración de una gran cantidad de funciones con parámetros externos. Y las funciones que implementa la integración numérica deben recibir un puntero a una función del tipo:

double f(double x, void * par) 

me gusta mucho funciones para anidarse esta manera por lo que mi código no se hinche con montones de funciones. Y espero poder compilarlo con ICC para acelerar un poco las cosas.

+3

Ustedes rocas !! ¡En menos de 2 minutos tuve respuestas completas! –

+21

Yo dawg, quiero que te gusten las funciones ... – GreenieMeanie

+2

Es por eso que necesito expresiones lambda en C. :( –

Respuesta

18

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

Su ejemplo es revisada:

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! 
} 

Dado que usted dice que las funciones tales como el integrador necesitan

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

no veo razón por la que realmente necesita en funciones anidadas todas.Yo esperaría 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' por el estilo) o C99; esta versión del código es sólo para C99, usando un compuesto literal 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 que tiene sólo unas pocas variaciones sobre los 'parámetros struct' tipo. Debe proporcionar nombres separados (suficientemente) significativos para las diversas funciones: solo puede tener una función llamada 'f' por archivo fuente.

El único beneficio pequeño y marginal de la versión de función anidada es que puede estar seguro de que ninguna otra función que no sea stuff llame al f. Pero dado el código de ejemplo, ese no es un beneficio importante; la definición estática de f significa que ninguna función fuera de este archivo puede invocarla a menos que pase un puntero a la función.

+0

Hola Jonathan, Mi razón de ser para usar funciones anidadas fue que, como f no es usuario en ningún otro lugar 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 integral). Pensé que dejar las funciones que se usan una sola vez flotando a través del código era una mala práctica. Si pudiera usar las funciones lambda como en python o Haskell sería swell. Pero necesito velocidad para este problema y no sé suficiente Haskell. –

3

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

0

No soy un experto, pero estoy dispuesto a apostar que esto no está explícitamente permitido o indefinido por la especificación C99, por lo que probablemente sea mejor mantenerse alejado de él.

30

Las funciones anidadas están disponibles como language extension in GCC, pero no son parte del lenguaje estándar, por lo que algunos compiladores no las permitirán.

+1

+1 - un rápido nota para el OP: Creo que está obteniendo el error en GCC aunque admite funciones anidadas porque ha escrito mal el nombre de la función. inner_funcion() debería ser inner_function(). –

+1

Ya veo. Gracias por la MUY rápida respuesta. 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 me atengo al uso de icc. –

+1

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

8

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 ortográfico. inner_funcion debe ser inner_function.

+1

Oh.Oops. Gracias, corregí el nombre de la función. –

+1

¿Por qué en el mundo agregaron una extensión no estándar a C? ¿Hay un interruptor de compilación para apagarlo? – jmucchiello

+0

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

1

Eso no es un código C válido, las funciones interiores no están soportados en C

1

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

1

funciones anidadas no son parte de los estándares C. Por lo tanto, no hay garantía de que funcione para todos los compiladores y definitivamente debe evitarse.

6

Como se menciona en muchas respuestas anteriores, las funciones internas no se admiten en C, sin embargo, las clases internas se pueden 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 debe implicar que pienso funciones internas son una buena idea en el uso que has demostrado.

años más tarde-edit:

C++ ahora nos permite utilizar lambdas como funciones internas. En el caso de mi ejemplo de juguete anterior, se vería muy parecido a éste:

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

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

Nota la variable local x es capturado de forma automática en el interior de la lambda, que es una característica muy agradable.

Más aquí: What is a lambda expression in C++11?

+0

¿Sería importante la pérdida de eficiencia si uso este código C++ en lugar de mi código C original? –

+0

Dudo que haya una pérdida significativa o notable de eficiencia. –

+1

¡Esto es genial! ¡Es casi como si tuviera las funciones internas de JavaScript otra vez! – portforwardpodcast

1

En el caso de que se preguntan cómo desactivar las extensiones del CCG y tal.

Puede usar el indicador -ansi que esencialmente establece el estándar en c89, y desactiva las características de GCC que son incompatibles con ISO C90.

Consulte el docs para obtener más información. Echa un vistazo a la bandera -std también.