31 votes

Fonctions à l'intérieur de fonctions en C

Je suis en train de créer un code similaire à celui-ci :

#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;
}

Cela se compile parfaitement dans GCC (sans aucun avertissement) mais ne se compile pas dans ICC.

La CCI donne :

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'est-ce que je fais de travers ?

Merci.

(edit) Désolé pour le mauvais exemple. Dans mon code original, j'ai un peu besoin de faire ce genre de choses. J'utilise un intégrateur numérique GSL et j'ai quelque chose comme :

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);

}

Et j'ai beaucoup de fonctions avec ce type de structure : elles sont le résultat d'une intégration d'une fonction avec beaucoup de paramètres externes. Et les fonctions qui implémentent l'intégration numérique doivent recevoir un pointeur vers une fonction de type :

double f(double x, void * par)

J'aimerais vraiment que les fonctions soient imbriquées de cette manière afin que mon code ne soit pas alourdi par de nombreuses fonctions. Et j'espère pouvoir le compiler avec ICC pour accélérer un peu les choses.

30voto

joshdick Points 585

Les fonctions imbriquées sont disponibles sous forme de extension du langage dans GCC mais ils ne font pas partie du langage standard, et certains compilateurs ne les autorisent donc pas.

25voto

Jonathan Leffler Points 299946

Tous les autres vous ont donné la réponse canonique "Les fonctions imbriquées ne sont pas autorisées en C standard" (leur utilisation dépend donc de votre compilateur).

Votre exemple révisé est le suivant :

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

Puisque vous dites que les fonctions telles que l'intégrateur ont besoin de

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

Je ne vois pas pourquoi vous avez besoin de fonctions imbriquées. Je m'attendrais à ce que l'on écrive :

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);
}

Le code ci-dessus devrait fonctionner en C89 (à moins qu'il n'y ait un problème avec l'initialisation de 'par' comme cela) ou en C99 ; cette version du code est pour C99 seulement, en utilisant un littéral composé pour le paramètre (section 6.5.2.5 Littéraux composés) :

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

Il y a de fortes chances que vous n'ayez que quelques variations du type "struct parameters". Vous devez fournir des noms distincts (suffisamment) significatifs pour les différentes fonctions - vous ne pouvez avoir qu'une seule fonction appelée "struct parameters". f par fichier source.

Le seul avantage marginal, minuscule, de la version avec fonctions imbriquées est que vous pouvez être sûr qu'aucune autre fonction que stuff appels f . Mais, compte tenu de l'exemple de code, ce n'est pas un avantage majeur ; la définition statique de f signifie qu'aucune fonction extérieure à ce fichier ne peut l'appeler, à moins qu'un pointeur sur la fonction ne lui soit transmis.

8voto

Nosredna Points 33670

Le langage C n'a pas de fonctions imbriquées. Les fonctions imbriquées de GCC sont une extension du langage.

Votre erreur d'exécution dans GCC est une erreur d'orthographe. inner_funcion devrait être inner_function .

7voto

Dan Olson Points 11210

Comme indiqué dans de nombreuses réponses ci-dessus, les fonctions internes ne sont pas prises en charge en C. Cependant, les fonctions internes classes peut être utilisé en C++ pour réaliser une opération similaire. Malheureusement, ils sont un peu difficiles à utiliser, mais cela peut être une option pour vous si cela ne vous dérange pas de compiler en C++.

Exemple non testé :

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

Notez que cette réponse ne doit pas impliquer que je pense que les fonctions internes sont une bonne idée dans l'utilisation que vous avez montrée.

Édition des années plus tard :

Le C++ nous permet désormais d'utiliser des lambdas comme fonctions internes. Dans le cas de mon petit exemple ci-dessus, cela ressemblerait à peu près à ceci :

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

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

Notez que la variable locale x est automatiquement capturée à l'intérieur du lambda, ce qui est une fonctionnalité très appréciable.

Plus d'informations ici : Qu'est-ce qu'une expression lambda en C++11 ?

3voto

Vous utilisez des fonctions imbriquées, ce que le langage C ne permet pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X