How to Have Functions Inside Functions in C++

Nested function in C

You cannot define a function within another function in standard C.

You can declare a function inside of a function, but it's not a nested function.

gcc has a language extension that allows nested functions. They are nonstandard, and as such are entirely compiler-dependent.

Functions inside functions in C

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.

Can we have functions inside functions in C++?

Modern C++ - Yes with lambdas!

In current versions of c++ (C++11, C++14, and C++17), you can have functions inside functions in the form of a lambda:

int main() {
// This declares a lambda, which can be called just like a function
auto print_message = [](std::string message)
{
std::cout << message << "\n";
};

// Prints "Hello!" 10 times
for(int i = 0; i < 10; i++) {
print_message("Hello!");
}
}

Lambdas can also modify local variables through **capture-by-reference*. With capture-by-reference, the lambda has access to all local variables declared in the lambda's scope. It can modify and change them normally.

int main() {
int i = 0;
// Captures i by reference; increments it by one
auto addOne = [&] () {
i++;
};

while(i < 10) {
addOne(); //Add 1 to i
std::cout << i << "\n";
}
}

C++98 and C++03 - Not directly, but yes with static functions inside local classes

C++ doesn't support that directly.

That said, you can have local classes, and they can have functions (non-static or static), so you can get this to some extend, albeit it's a bit of a kludge:

int main() // it's int, dammit!
{
struct X { // struct's as good as class
static void a()
{
}
};

X::a();

return 0;
}

However, I'd question the praxis. Everyone knows (well, now that you do, anyway :)) C++ doesn't support local functions, so they are used to not having them. They are not used, however, to that kludge. I would spend quite a while on this code to make sure it's really only there to allow local functions. Not good.

Can we declare functions inside functions?

Yes, you can declare, but you cannot define. Also, you can declare function as many times you want, but define only once.

declaring function inside a function in C

I suppose you are reading the K&R C Programming Language and perhaps the Second Edition with ANSI C? There is a PDF at https://hassanolity.files.wordpress.com/2013/11/the_c_programming_language_2.pdf and on page 87 is a discussion of recursion using the quick sort algorithm.

See this Wikipedia topic comparing and contrasting various C standards https://en.wikipedia.org/wiki/ANSI_C

The K&R C books are old style C as the Second Edition copyright is 1988. Lots of good material there but it needs to be read from the perspective of being older style and the C standards have changed since ANSI C. The main thing has been better specifications about what compilers are supposed to declare as errors and warnings. There were things perfectly acceptable in ANSI C that are no longer acceptable with the modern C standards. A lot of work has gone into attempting to provide better static checking by compilers by tightening up the C programming language specifications and providing a few extra keywords and syntax.

There either should be a forward declaration for swap() or the definition of the function with its source code should appear before the function is actually used. This allows the C compiler to check the usage of a function against its declaration or definition in order to check for possible usage errors.

However with the C programming language if you use a function before it is either defined or declared you will typically get a warning such as this warning from Visual Studio 2013 warning C4013: 'swap' undefined; assuming extern returning int.

Some compilers, recent versions of clang and gcc come to mind as well as Visual Studio 2015, have begun implementing C11. Some compilers provide additional options to improve warnings and/or to turn some kinds of warnings into errors.

For example if I have the following source code in a file testit.c (notice the .c file extension for C source code) and compile with Visual Studio 2013 using a warning level of 4, I will get a set of warnings but no errors. Visual Studio compiles this as C source using the standards and rules for C which are looser than those for C++ even for the same syntax.

I compiled two different versions of this source, one with the forward declaration on line 2 commented out and one with it uncommented. Notice from the warnings that the C compiler of Visual Studio allows a function to be used without a forward declaration.

Notice when the forward declaration on line 2 is uncommented in the second run there is a warning about putting a forward declaration for a function within a function scope: warning C4210: nonstandard extension used : function given file scope.

Also notice that with the forward declaration available in the second run, the compiler is able to identify possible usage errors and issue warnings and in one case issue an actual error.

Notice that the number of arguments varies in both the first and second compile but only in the second compile with the forward declaration uncommented and available for the compiler do we see warnings about extra arguments.

int func1() {                        // line 1
// int swap(int a, int b); // line 2, forward declaration for function swap

int j = swap(1, 2);

return 0;
}

int func2() { // line 9
struct {
int a;
int b;
int c;
} mm = { 0 };

int k = swap(4, 5, 8); // line 16

float ff = swap(4.0, 5.0, 8.0); // line 18

int k2 = swap(mm, 2, 3); // line 20

return 1;
}

int swap(int a, int b) { // line 25
return a + b;
}

The warnings are:

1>------ Build started: Project: ConsoleApplication3, Configuration: Debug Win32 ------
1> testit.c
1>c:\users\projects\consoleapplication3\testit.c(4): warning C4013: 'swap' undefined; assuming extern returning int
1>c:\users\projects\consoleapplication3\testit.c(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4244: 'initializing' : conversion from 'int' to 'float', possible loss of data
1>c:\users\projects\consoleapplication3\testit.c(16): warning C4189: 'k' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(20): warning C4189: 'k2' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4189: 'ff' : local variable is initialized but not referenced
1> ConsoleApplication3.vcxproj -> C:\Users\Projects\Debug\ConsoleApplication3.exe

If I then uncomment the forward declaration for the function swap() I see the following compiler output of warnings along with errors:

1>------ Build started: Project: ConsoleApplication3, Configuration: Debug Win32 ------
1> testit.c
1>c:\users\projects\consoleapplication3\testit.c(2): warning C4210: nonstandard extension used : function given file scope
1>c:\users\projects\consoleapplication3\testit.c(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(16): warning C4020: 'swap' : too many actual parameters
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4244: 'function' : conversion from 'double' to 'int', possible loss of data
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4020: 'swap' : too many actual parameters
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4244: 'initializing' : conversion from 'int' to 'float', possible loss of data
1>c:\users\projects\consoleapplication3\testit.c(20): error C2440: 'function' : cannot convert from '' to 'int'
1>c:\users\projects\consoleapplication3\testit.c(20): warning C4024: 'swap' : different types for formal and actual parameter 1
1>c:\users\projects\consoleapplication3\testit.c(20): warning C4020: 'swap' : too many actual parameters

Now the C++ programming language is different and does not allow this kind of looseness. Which is why though C++ shares a history with C, C++ is a different though related language.

If I copy the same source into a file testit2.cpp then compile I will see different errors.

First with the forward declaration of swap() commented out.

1>  testit2.cpp
1>c:\users\projects\consoleapplication3\testit2.cpp(4): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(16): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(18): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(20): error C3861: 'swap': identifier not found

And again with the forward declaration uncommented.

1>  testit2.cpp
1>c:\users\projects\consoleapplication3\testit2.cpp(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit2.cpp(16): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(18): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(20): error C3861: 'swap': identifier not found

And finally if I move the forward declaration of swap() out of the scope of function func1() into file scope so that it is now line 1 then I will see the following, different errors:

1>  testit2.cpp
1>c:\users\projects\consoleapplication3\testit2.cpp(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit2.cpp(16): error C2660: 'swap' : function does not take 3 arguments
1>c:\users\projects\consoleapplication3\testit2.cpp(18): error C2660: 'swap' : function does not take 3 arguments
1>c:\users\projects\consoleapplication3\testit2.cpp(20): error C2660: 'swap' : function does not take 3 arguments

Function inside function in C

You are using an extension of the GNU C Compiler which allows the declarations of nested functions. The error comes from the fact, that forward declarations of nested functions under GCC's extension need to be prepended with the auto keyword.

int a=20,b=11;
int main()
{
int a=5, b=60;
auto int func(); // <--------- here
func(); // <- call it
printf("\nI am in main-1");

int func(){
printf("\nI am in funct");
return 1;
}

printf("\nI am in main-2");
return 0;
}

See http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html for more details.

Defining a Function inside of main()

Nested functions (functions within functions) is a GNU only extension and not part of any regular C standard. Any other compiler will fail to compile this. Due to this I would highly discourage the use of nested functions.

Declare your structs and functions outside. You can then always pass a pointer to your data structures to your function.

struct s {...};

void foo(struct s *, ...);

int main() {

struct s mystruct;
foo(&mystruct, ...);

}

C calling nested function inside another nested function

From gcc documentation nested functions:

If you try to call the nested function through its address after the containing function exits, all hell breaks loose.

The function void foo is defined inside function Wrapper and the address to the function foo is returned from Wrapper. Then you call the function after the function Wrapper exits. As documentation states your code makes "all hell break loose".

Think of a nested function as a variable allocated on stack. When the function returns, the nested function stops existing.

the trampoline nested function can't access to the trampoline variables, in this case the float r.

The variable r has scope only within Wrapper function. Once Wrapper exits, the variable r stops existing.

auto void foo();
auto void foo2();

That's odd. There's no need to write that. Just write the function - it's like auto by default anyway.

Why can't I define a function inside another function?

It is not obvious why one is not allowed; nested functions were proposed a long time ago in N0295 which says:

We discuss the introduction of nested functions into C++. Nested
functions are well understood and their introduction requires little
effort from either compiler vendors, programmers, or the committee.
Nested functions offer significant advantages, [...]

Obviously this proposal was rejected, but since we don't have meeting minutes available online for 1993 we don't have a possible source for the rationale for this rejection.

In fact this proposal is noted in Lambda expressions and closures for C
++
as a possible alternative:

One article [Bre88] and proposal N0295 to the C
++ committee [SH93] suggest adding nested functions to C
++ . Nested functions are similar to lambda expressions, but are defined as statements within a function body, and the resulting
closure cannot be used unless that function is active. These proposals
also do not include adding a new type for each lambda expression, but
instead implementing them more like normal functions, including
allowing a special kind of function pointer to refer to them. Both of
these proposals predate the addition of templates to C
++ , and so do not mention the use of nested functions in combination with generic algorithms. Also, these proposals have no way to copy
local variables into a closure, and so the nested functions they
produce are completely unusable outside their enclosing function

Considering we do now have lambdas we are unlikely to see nested functions since, as the paper outlines, they are alternatives for the same problem and nested functions have several limitations relative to lambdas.

As for this part of your question:

// This is legal, but why would I want this?
int two(int bar);

There are cases where this would be a useful way to call the function you want. The draft C++ standard section 3.4.1 [basic.lookup.unqual] gives us one interesting example:

namespace NS {
class T { };
void f(T);
void g(T, int);
}

NS::T parm;
void g(NS::T, float);

int main() {
f(parm); // OK: calls NS::f
extern void g(NS::T, float);
g(parm, 1); // OK: calls g(NS::T, float)
}


Related Topics



Leave a reply



Submit