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.
Related
I'm new to C. I cannot understand the result in following code. I use goto and jump the declaration of int a[N] array and int x. Although x is not initilized to 10, I can still get access to these variables.
#include <stdlib.h>
#include <stdio.h>
#define N 4
void printArray(int a[], int length) {
for (int i = 0; i < length; i++) {
printf("%d, ", a[i]);
}
printf("\n");
}
int main(void) {
goto done;
int a[N];
int x=10;
printf("x=%d\n", x);
done:
for (int i = 0; i < N; i++) {
a[i] = i;
}
printArray(a, N);
printf("x=%d\n", x);
return EXIT_SUCCESS;
}
result
0, 1, 2, 3
x=0
My question:
Why I can get access to these variables whose declarations have been jumped? How are variables declared in C? It seems that variable declarations are not run line by line.
Aside from "Variable Length Arrays (VLAs)", an automatic variable's "lifetime extends from entry into the block with which it is associated until execution of that block ends in any way." (§6.2.4) The initialization (if any) occurs a bit later, when the program passes through the declaration. It's legal to jump over the declaration if the program does not depend on the initialization of the variable. But regardless of whether the initialization will eventually happen, the variable exists from the moment your program enters the block, however that is done. (Jumping into a block from outside is also legal, and may also prevent initialization. But as soon as you're in the block, the variable exists.)
If the program attempts to read the value of an uninitialised variable, it receives an indeterminate value. (Most compilers attempt to detect the possibility that this might happen, but you'll need to enable warnings in order to see the report.)
The consequence of "hoisting" the lifetime of a variable to its enclosing block is that there is a portion of the program in which the variable exists but is not visible (since its scope starts where it is defined.) If you save the address of the variable and then jump back into this region of the program, you will be able to access the value of the variable through the pointer, which shows that scope and lifetime are distinct.
If the variable is a VLA, then it's lifetime starts at the declaration and the compiler will not allow you to jump over the declaration. VLAs cannot be initialised, so you must assign a value to every element in a VLA which you intend to access. Not all compilers implement VLAs. Your example does not show a VLA, since N is a macro which expands to an integer constant.
For objective info about the C standard, see rici's answer.
But I see you are asking how this behavior is possible from a C program, and remarking that:
It seems that variable declarifications are not run line by line.
In fact, most computer languages are not run line by line. There is almost always some kind of multi-line parsing step that happens beforehand. For example, even the Bash shell language is processed multiple lines at a time. When Bash finds a while loop, it seems to do extra parsing to make sure the done command is found before it runs any of the code in the while loop. If you don't believe me, try running this Bash script:
while [ 1 ]
do
echo hi
sleep 1
# file terminates before the expected "done" command that ends the loop
Similarly, a C compiler is capable of parsing your code, checking its syntax, and checking that your program is well-formed before it even executes a single line of your code inside any of your functions. When the compiler sees that you are using a or x, it knows what those things are because you declared them above, even if the execution of the program never passed through those lines.
One way that you could imagine that a compiler might work is that (after checking the validity of your code) it moves all the local variable declarations to the top of the function. So your main function might look like this in the internal representation in the compiler:
int main(void) {
int a[N];
int x;
int i;
goto done;
x = 10;
printf("x=%d\n", x);
done:
for (i = 0; i < N; i++) {
a[i] = i;
}
printArray(a, N);
printf("x=%d\n", x);
return EXIT_SUCCESS;
}
This could actually be a useful transformation that would help the compiler generate code for your function because it would make it easy for the compiler to allocate memory on the stack for all your local variables when the function starts.
This question already has answers here:
func() vs func(void) in C99
(4 answers)
Difference between int main() and int main(void)?
(10 answers)
Closed 4 years ago.
What is the difference between these two programs?
The 1st one i am getting 4,3,2,1 and 2nd one is compilation error.
#include <stdio.h>
int main()
{
static int i = 5;
if (--i){
printf("%d ", i);
main(10);
}
}
and
#include <stdio.h>
int main(void)
{
static int i = 5;
if (--i){
printf("%d ", i);
main(10);
}
}
When you define a function like this:
int func() { ... }
It says that the function takes an indeterminate number of arguments and returns an int. So you can legally pass any number of arguments of any type (although you won't be able to access them).
When you define a function like this:
int func(void) { ... }
It says that the function takes no arguments. Attempting to pass any arguments to this function will result in a compile time error.
On a side note, recursively calling the main function is not a good idea. You're better off either calling another function which is recursive or just using a loop.
The appearance of a solitary void in a parameter list explicitly tells the compiler "this function takes no arguments".
In the first code example, calling main recursively is permitted since there is no argument list, which permits any number of arguments (this may have been changed in a more recent C standard than the one supported by your compiler; I forget the specifics).
Variables declared static are stored in the process' data section rather than in stack memory, so they persist beyond their scope and retain their value across function calls, so i decrements on each call until it reaches zero and your program hits the base case (don't enter the if statement), and terminates.
Following simple C program outputs 42 to my surprise. I expected it to output a garbage value or 0, since stack frames are different for foo() and bar(). How the output is deterministic to be 42 ?
#include <stdio.h>
void foo(void){
int a;
printf("%d\n",a);
}
void bar(){
int a=42;
}
int main(){
bar();
foo();
return 0;
}
>>gcc -o test test.c
>>./test
42
When I instruct compiler to optimize the code, it prints garbage!
>>gcc -O -o test test.c
>>./test
2487239847
Yes, the value 42 is a garbage. Here is the explanation for it:
Every function in stack, starts similar to this order
Parameters of the function
Return value of the function
EBP( Which stores previous frame pointer)
Exception handler frame
Local variables
Buffer
callee save register
In the above example, main() is called and follows the procedure as above.
Then it encounters the bar() follows 1,2,3,4 steps mentioned and then stores the local variable a=42 in the memory(5) then 6,7 are followed then it will come out of the memory.
Then it encounters the foo() follows 1,2,3,4 steps as same in the memory location that bar() had. And you declared a local variable called a which will point to same memory location that bar() holding the local variable a=42. So it is giving the same value 42 when you are printing, which is actually a garbage value.
To validate this, try this example: This prints 7
#include <stdio.h>
#include <string.h>
void foo() {
int b;
printf("%d\n",b);
}
void zoo() {
int dummy = 7;
}
void bar(){
int a1=3;
}
int main(){
bar();
zoo();
foo();
return 0;
}
Ref: Doc
The function calls go on stack (their activation records), in this case the two functions foo and bar are identical in terms of parameters, return type and the local variables within each function. So the first call puts something on the stack and once done its activation record is popped out but not cleaned (compiler does not generate code to clean things up). Now the second function call essentially ends up using the same memory location and therefore gets the value from a previous call using same memory area. The values that are not initialized in a function are considered undefined. In the foo and bar case we got to the same value due to similar signature of two functions and same type and location of the variable. Try adding two integers or integer and a float in one function and reverse the order in next and you'll see the effects. Of course when you call the optimizer it might place things on register and as a result you may get undefined values when the compiler sees no scope for optimization as in case of foo.
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.
Hi can anyone tell me would variable a remain in memory or would it get destroyed immediately.
#include <stdio.h>
int main()
{
{
int a=1;
lab:
printf("Value of a : %d",a);
}
return 0;
}
would int a still remain in memory or not ?
Nope, a has local scope (declared between brackets) so at the closing brace it will be cleaned up.
If you want it to persist for the entirety of the program, either declare it as static or put it outside of any braces, preferably before you use it.
This has the added benefit of having the compiler initialise it for you.
You can try out the following:
#include <stdio.h>
int a;
int main()
{
static int b;
int c;
printf("%d, %d, %d\n", a, b, c); /* a and b should print 0, printing c is undefined behaviour, anything could be there */
return 0;
}
As Bathsheba pointed out, static variables should be used judiciously if used in a multi-threaded environment.
a is destroyed (popped from the stack) when you get to the } following the line with printf , so no, it does not remain in memory at your comment line.
First of all: It is not implementation specific. The C standard explicitly says, that leaving a block destroys an object with auto (local declared) lifetime:
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.
[ISO/IEC9899:TC3, 6.2.4, 5]
Of course, this is hard to test, because it loses it scope, too, in this case. (The other way around is easy to test.) But this is important for a formal reason: If you have a pointer to that object, which lives longer than the object, the program is always incorrect and the behavior is undefined – even an implementation let the object being alive. (Undefnied behavior includes that everything works fine.)