31

I'm making a code that is similar to this:

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

This compiles perfectly in GCC (with no warnings) but fails to compile in ICC.

ICC gives:

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)

What am I doing wrong?

Thanks.

(edit) Sorry for the poor example. In my original code I kinda need to do this stuff. I'm using a GSL numerical integrator and have something like:

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

}

And I have lots of functions with this kind of structure: they are the result of an integration of a functions with lots of external parameters. And the functions that implements numerical integration must receive a pointer to a function of type:

double f(double x, void * par)

I would really like functions to be nested this way so my code doesn't bloat with lots and lots of functions. And I hope I could compile it with ICC to speed things a bit.

Rafael S. Calsaverini
  • 13,582
  • 19
  • 75
  • 132

10 Answers10

30

Nested functions are available as a language extension in GCC, but they are not part of the standard language, so some compilers will not allow them.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
joshdick
  • 1,042
  • 4
  • 13
  • 20
  • 1
    +1 - a quick note for the OP: I think you're getting the error in GCC even though it supports nested functions because you've misspelled the function name. inner_funcion() should be inner_function(). – Michael Burr Jun 05 '09 at 19:21
  • 1
    I see. Thanks for the VERY quick answer. I was using this without noticing it wasn't standard. That's very bad. I see my code will be very difficult to understand if I stick to using icc. – Rafael S. Calsaverini Jun 05 '09 at 19:27
  • 1
    The last time I moved from JavaScript to C, I tried using nested functions. I love nested functions. But don't give up on making your C easy to read, understand, and debug. It's doable. – Nosredna Jun 05 '09 at 19:56
25

Everybody else has given you the canonical answer "Nested functions are not allowed in standard C" (so any use of them depends on your compiler).

Your revised example is:

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

Since you say that the functions such as the integrator need

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

I don't see why you really need nested functions at all. I would expect to write:

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

The code above should work in C89 (unless there's an issue with initializing 'par' like that) or C99; this version of the code is for C99 only, using a compound literal for the parameter (section 6.5.2.5 Compound literals):

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

The chances are excellent that you have only a few variations on the 'struct parameters' type. You do need to provide separate (sufficiently) meaningful names for the various functions - you can only have one function called 'f' per source file.

The only marginal, tiny benefit of the nested function version is that you can be sure that no other function than stuff calls f. But given the example code, that is not a major benefit; the static definition of f means that no function outside this file can call it unless passed a pointer to the function.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Hi Jonathan, my rationale for using nested functions was that, since f is not user anywhere except to calculate the integral, I thought this was a good way to make the code more readable for myself. But maybe not. I have many functions to integrate (it is actually a solution of a system of coupled equations in which each equation is an integral) I thought that leaving functions that are used only once floating through the code was bad practice. If I could use lambda functions as in python or Haskell it would be swell. But I need speed for this problem and don't know sufficient Haskell. – Rafael S. Calsaverini Jun 08 '09 at 00:40
8

C doesn't have nested functions. GCC's nested functions are an extension to the language.

Your runtime error in GCC is a spelling error. inner_funcion should be inner_function.

Yamaneko
  • 3,433
  • 2
  • 38
  • 57
Nosredna
  • 83,000
  • 15
  • 95
  • 122
7

As mentioned by many answers above, inner functions are not supported in C. However, inner classes can be used in C++ to accomplish a similar thing. Unfortunately, they are a bit unwieldy to use, but it might be an option for you if you don't mind compiling as C++.

Untested example:

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

Note that this answer shouldn't imply that I think inner functions are a good idea in the usage you've shown.

Years-later edit:

C++ now allows us to use lambdas as inner functions. In the case of my toy example above, it would look much like this:

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

Note the local variable x is automatically captured inside of the lambda, which is a very nice feature.

More here: What is a lambda expression in C++11?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Dan Olson
  • 22,849
  • 4
  • 42
  • 56
3

You are using nested functions - C does not support such things.

1

That is not a valid C code, inner functions are not supported in C

Naveen
  • 74,600
  • 47
  • 176
  • 233
1

local function definitions inside a function are illegal in C.

aJ.
  • 34,624
  • 22
  • 86
  • 128
1

Nested functions are not part of the C standards. There is therefore no guarantee that it will work for all compilers and should definitely be avoided.

Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
1

In the event you were wondering how to turn off GCC extensions and such.

You can use the -ansi flag which essentially sets the standard to c89, and turns off GCC features which are incompatible with ISO C90.

See the docs for more information. Check out the -std flag too.

Nick Presta
  • 28,134
  • 6
  • 57
  • 76
0

I'm not an expert, but I'm willing to bet this is either explicitly not allowed or undefined by the C99 spec, so it's probably best to stay away from it.

pjbeardsley
  • 1,491
  • 1
  • 13
  • 17