I am starting to learn functional programming and wanted to see if I could get away with closures in C. In order to reproduce first example from Wikipedia - Closures I coded up the following code:
#include <stdio.h>
void closure (int(** f)(int), int *x) {
int fcn(int y) {
return *x + y;
};
*f = fcn;
}
int main()
{
int x = 1;
int(* f)(int);
closure(&f, &x);
printf("%d", f(2));
return 0;
}
It was compiled (gcc 4.8.2. on Ubuntu 14.04.) and it works, it prints out 3. Since the lack of my expertise in C (only basic courses on college), my question is, is there something seriously wrong with this code? I was taught function definitions should be global and I was never expecting this to work...
Edit:
And why is it, when I change the main function like this:
int main()
{
int x = 1;
int(* f)(int);
closure(&f, &x);
printf("%d", f(2));
printf("%d", f(3)); // the only difference
return 0;
}
I get Segmentation fault?
Your code works because gcc has a language extension that supports nested functions.
However, in standard C, you cannot define a function within another function.
Gnu Nested Functions
If you try to call the nested function through its address after the containing function exits, all hell breaks loose. If you try to call it after a containing scope level exits, and if it refers to some of the variables that are no longer in scope, you may be lucky, but it's not wise to take the risk. If, however, the nested function does not refer to anything that has gone out of scope, you should be safe.
First of all, your program invokes undefined behaviour. That's because the function fcn defined in the function closure is local to it. fcn no longer exists once closure returns. So the printf call
printf("%d", f(2));
invokes undefined behaviour by calling f(2) because f points to the function fcn which is not in scope.
The C language does not have closure and that's because functions in C are not first-class objects. What this means is functions cannot be passed to other functions or cannot be returned from a function. What actually gets passed or returned is a pointer to it.
Please note that there is a difference between nested functions and closure. What you see is a GCC extension for nested function. It is not part of the C standard.
Related
I saw the link http://www.cs.uregina.ca/Links/class-info/cplusplus/Standards/Disk10/aliasing_c.html about aliasing in c. The program there is shown below.
/********************************
An example of aliasing in C.
Output:
3
3
********************************/
#include < stdio.h >
int main()
{
int G_Var = 2;
/* call SomeFunction with the Global Variable as a parameter */
SomeFunction(G_Var);
return 0;
}
/* InputVar becomes an alias fo G_Var */
void SomeFunction(int &InputVar)
{
int G_Var;
int InputVar;
/* Global Variable is set to new value */
G_Var = InputVar + 1;
/* Equivalent to G_Var = G_Var + 1 */
printf("%i\n", InputVar);
printf("%i\n", G_Var);
}
Is the code correct and is working according to what is commented in the code?
Whoever wrote the link was severely incompetent and shouldn't be teaching C. They should rather enlist in a beginner's class themselves.
int G_Var = 2; is not a global variable, it is a local one with automatic storage duration. Both the one in main() and the one inside the function.
The code posted is C++, not C. C does not have references.
The term alias/aliasing refers to when several pointers (or C++ references) may be assumed to point at the same memory location.
int InputVar; in the function conflicts with the parameter name so the code doesn't make any sense. In case there were no name conflict, the variable would be uninitialized and then used, which would be senseless.
Is the code correct and is working according to what is commented in the code?
Whoever wrote this example was so confused that it's really hard to be telling what they are trying to teach, or in which language for that matter. The code does not compile for multiple fundamental reasons. Just forget about this mess.
Four things to say:
C does not have C++-kind of aliases/references. It is a C++ feature only.
So,
/* InputVar becomes an alias fo G_Var */
void SomeFunction(int &InputVar)
is wrong.
G_Var is not a global variable. You declare it two times to be local to main and SomeFunction. If you want to declare G_Var as global variable it has to be declared once at global scope, not inside of a function, and only access it by its name, not declaring its type twice.
But beside that the use of global variables is deprecated. Rather use parameter passing.
SomeFunction() isn't declared before the call to it in main(). Usually this would give you a diagnostic as the compiler don't know what SomeFunction() is.
InputVar is used as reference parameter, but also declared twice in SomeFunction. Here is a conflict.
I guess you never compiled this code before asking, which is a fault. It would have answered many questions of yours including the main one.
"Is the illustration on Aliasing in C correct?"
"Is the code correct and is working according to what is commented in the code?"
No, it isn't. The whole code is defective.
It gives the impression that the authors didn't knew how to either write correct C nor C++ code.
The GNU C compiler contains a nice extension to the C language, called Nested Functions.
However, the documentation is unclear in some points. For example, it says that
It is possible to call the nested function from outside the scope of its name by storing its address or passing the address to another function [...]
If you try to call the nested function through its address after the containing function exits, all hell breaks loose.
If you try to call it after a containing scope level exits, and if it refers to some of the variables that are no longer in scope, you may be lucky, but it’s not wise to take the risk.
If, however, the nested function does not refer to anything that has gone out of scope, you should be safe.
So on one hand, it says that if you call a nested function after the containing function exits, "all hell breaks loose", but a few sentences ahead it says that there are circumstances in which it is fine to do so.
I imagine that by "things going out of scope" they mean automatic variables, so in particular it should be safe to refactor
static int f() { ... }
int outer() {
... // some use of f
}
into
int outer() {
int f() { ... } // f does not refer to outer's local variables
... // some use of f
}
if there are no other uses of f in the module than those in the outer function, even assuming that the outer function somehow leaks the address of f beyond its own scope.
However, I was surprised to find out that the following code doesn't compile
int main(void) {
void nested_function(void) {}
static const struct { void (*function_pointer)(void); } s = {
.function_pointer = nested_function
};
return 0;
}
with the complaint that initializer element is not constant (i.e. nested_function).
Is there any reason for this limitation? (I can't imagine the address of a function being non-constant, even if it is nested)
In the current GCC implementation, an unnecessary static chain pointer for nested functions is only omitted during optimization. It is not reflected in the type system (unlike a C++ lambda that does not bind anything). Without optimization, the compiler has to create a trampoline on the stack, so the function address is actually non-constant in that case.
I'm reading a C programming book, The C Programming Language (K & R, 2nd Edition). I got to know the facts about external variables in the book, but I found something different when I practiced the principles by myself. The book says:
"... because external variables remain in existence permanently, rather than appearing and disappearing as functions are called and exited, they retain their values even after the functions that set them have returned."
However, when I code like this:
#include <stdio.h>
int i = 0;
void foo();
main()
{
foo();
printf("%d", i);
return 0;
}
void foo()
{
i = 1;
}
The program prints 1 instead of 0 which is the original value of the external variable i. So I wonder where I get mistakes while thinking about the principle and how to understand it.
...they retain their values even after the functions that set them have returned.
I'm guessing it's a question of interpretation on your part.
Given that the variable is global, every time you change it, in any function, it will assume and retain that value until it is next modified.
Take the function:
int i = 0;
void foo();
int main()
{
int x = 0;
foo(x);
printf("%d", i);
printf("%d", x);
return 0;
}
void foo(int x)
{
x = 1;
i = 1;
}
result: x = 0 i = 1
x is passed by value, essentially, a copy of it, so as soon as the function goes out of scope, i.e. returns, the copy is discarded. i is global so you don't even need to pass it; every function is aware of its existence and will change its value.
Opposite to what you think this phrase
...as functions are called and exited, they remain their values even
after the functions that set them have returned
means that after exiting a function a variables with the external linkage keeps the value assigned to it in the function. And your program demonstrates this.
Pay attention to that now according to the C Standard the function main without parameters shall be declared like
int main( void )
There is no default type int of a function though some compilers keep the backward compatibility.
It's K&R-C and here is the code: http://v6shell.org/history/if.c
Look at the main-Method. There is this line "if(exp())".
But the function exp is declared as: exp(s). So it needs an argument.
Why does this work? And why would you do this?
Ultimately, it is a bug in the Unix V6 shell support command, if.
The code for the function is:
exp(s) {
int p1;
p1 = e1();
if (eq(nxtarg(), "-o")) return(p1 | exp());
ap--;
return(p1);
}
The function parameter s, implicitly of type int (as is the function iteself), is actually unused in the function, so the bug is the presence of s, not the absence of an argument in the calls to exp(). All the calls with zero actual arguments are correct.
If you look at the definition:
exp(s) {
int p1;
p1 = e1();
if (eq(nxtarg(), "-o")) return(p1 | exp());
ap--;
return(p1);
}
s is not used
C doesn't require compile time type checking. It doesn't even require function parameters to be checked. Everything is a/series of bytes
Why does C not do any of those checks? From what I hear it's 'cause during first few years of C, computers were fairly weak. Doing those checks would require multiple passes to scan the source code, which basically increases compile time by a magnitude of n passes. So it just does a single pass, and takes every name as is, which is why function overloading is not supported
So if the definitions did make use of s in some way, you would most likely get some horrible runtime error with wonderful outputs to the console
This is because in c
The compiler will not be able to perform compile-time checking of argument types and arity when the function is applied to some arguments. This can cause problems
Calling an undeclared function is poor style in C (See this) and illegal in C++
for example-
#include<stdio.h>
void f(int x);
int main()
{
f(); /* Poor style in C, invalid in C++*/
getchar();
return 0;
}
void f(int x)
{
printf("%d", x);
}
This program will work but shouldn't be used.See this Wiki link for more.
I read somewhere that nested functions are permissible in C (at least the GNU compiler allows it). Consider the following code:
/* nestedfunc.c */
#include <stdlib.h> /* for atoi(3) */
#include <stdio.h>
int F (int q)
{
int G (int r)
{
return (q + r);
}
return (G (5));
}
int main (int argc, const char* argv[])
{
int q = 0;
if (argc > 1)
{
q = atoi (argv[1]);
}
printf ("%d\n", F (q));
return 0;
}
Compiling and running:
gcc -o nestedfunc -O2 -s -Wall nestedfunc.c
me#mybox:~/college/c++/other stuff$ ./nestedfunc 8
13
me#mybox:~/college/c++/other stuff$
I've also read that some other programming languages support these. My question is this: What useful purpose does a nested function have? Thanks in advance.
Nested functions can access the outer function's locals. Somewhat like closures, you can take a pointer to a nested function and pass this pointer to other functions, and the nested function will have access to the current invocation's locals (bad things happen if this invocation has already returned). Because the C runtime system is not designed for this, a function pointer is generally just a pointer to the first instruction of the function and pointers to nested functions can only be done by writing some code on the stack and passing a pointer to that. This is a bad idea from a security perspective.
If you want to use nested functions, use a language with a runtime system with proper support for them. To achieve a similar result in C, put "the outer function's locals" in a context structure and pass this along manually.
Nested functions provide encapsulation through lexical scope.
In your example, G() can only be called by F() and by other functions defined within F().
In general, a nested function is usually a helper function, which is only used inside one other function. It's sort of like a static function (with file scope) but even more localised (only function scope).
Nested functions are not standard C, so there's little reason to use them in that language.
In other programming languages (like Python, Ruby for example) functions are first class objects. You have closures which are powerful abstraction concept. In python you can do this:
def curry(func):
from inspect import getfullargspec
args = getfullargspec(func)
num_args = len(args[0])
def new_func(list_args, *args):
l = len(list_args) + len(args)
nl = list_args + list(args)
if l > num_args:
raise TypeError("Too many arguments to function")
elif l == num_args:
return func(*nl)
else:
return lambda *new_args: new_func(nl, *new_args)
return lambda *args: new_func([], *args)
That is curry decorator which takes a function and makes it curried.