Call stack is reused between 2 function calls - c

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.

Related

Passing variables between functions in c with out using global variables

I am trying to print the value of a local variable inside of main, from another function without using global variables. What would be the best way to do so?
#include <stdio.h>
int function1();
int main(void) {
int hello=10;
printf(function1());
}
int function1(int ip){
printf("hello%d",ip);
}
I am expecting the 10 to be printed next to the "hello" but instead get a 0.
You need to call the function passing the value (or variable) required.
int function1(int);
int main(void)
{
int hello=10;
function1(hello);
function1(130);
}
int function1(int ip)
{
return printf("hello - %d\n",ip);
}
https://godbolt.org/z/97o3dPWzj
change
int function1();
to
int function1(int);
and
printf(function1());
to
function1(hello);
"I am expecting the 10 to be printed next to the "hello" but instead get a 0."
There are already examples of working versions of your code in the other answers, but little is said in the way of explanation. I will try to do that here, and offer some general suggestions.
Although your code compiles, it does so with warnings and when run, produces run-time errors. The information resulting from both of these, if heeded would likely provide a guide to addressing most of your issues. (If using GCC for example, you can set warnings to -Wall). To illustrate, here is an image showing line numbers and the warning that correspond with them on my system (not GCC, but warning are turned on)
Build warnings:
And finally, run-time error:
From these you can begin to derive some of the following observations (others listed are my own.)
The signature of a function prototype must match its implementation. (for function1, they do not)
If the prototype of a function is non-void, then it should return a value.
If a function returns a value, its return value should not be ignored.
The warning of an unused variable pointed out that you probably intended to use it as an argument here: function1()
See comments below for other clarifications:
int function1();//this prototype is incomplete, and is inconsistent
//with the signature of its implementation
int main(void) {
int hello=10;
printf(function1());//because function1 is not returning a value, your code outputs a 0
//Function1 prototype requires it to pass an argument
// non-void function should return a value here
}
int function1(int ip){//signature of this implementation disagrees with its prototype
//because there is no value passed, ip can be any value
printf("hello%d",ip);
// non-void function should return a value here
}

Are uninitialized local variables in C static by default?

I recently learnt about the static variables, that they retain their values in between various function calls. Then I wrote some code to test it, then hopefully it worked perfect. But then I accidentally removed the static keyword at the beginning of the declaration of the local variable and there came the actual problem.
The output of both the programs are similar, besides the absence of the static keyword during the declaration.
Code without any static declaration:
#include <stdio.h>
void up();
int main(){
up(); //Output: 1
up(); //Output: 2
return 0;
}
void up(){
int stvar;
stvar++;
printf("%d\n", stvar);
}
Code with static declaration:
#include <stdio.h>
void up();
int main(){
up(); //Output: 1
up(); //Output: 2
return 0;
}
void up(){
static int stvar;
stvar++;
printf("%d\n", stvar);
}
Then finally I tried this one, by just initializing the local variable:
#include <stdio.h>
void up();
int main(){
up(); //Output: 1
up(); //Output: 1
return 0;
}
void up(){
int stvar = 0;
stvar++;
printf("%d\n", stvar);
}
This time the local variable shows it natural behaviour.
I just wanted to know if uninitialized local variables are static by default?
No, they are not static by default. In principle, the initial value can be anything at all. Using the value could even be undefined behaviour. In practice, the compiler picks a memory location for the variable on the stack, and the variable's initial value is whatever happens to already be in that memory location.
Since you don't run any other code between the first up() and the second up(), in practice your program is likely to pick the same location twice and therefore it still has the previous value. If you called another function in between, that function's local variables would go in the same space previously used by up()'s local variables, which would overwrite the value from the first up().
You certainly can't rely on it. Even if you don't call any other functions in-between, the compiler might add one "secretly" (for various reasons). Or the compiler may decide to adjust the stack between the two calls to up so each call might get a different stack location for its local variables.
You also aren't guaranteed that the first value is 0. Because it's whatever happens to be at that memory location already, it could be something left over from a previous function. main isn't the first function that gets called; there is some function in the standard library which does set-up work before it calls main.
Using non initialized automatic variable is dangerous.
It is Undefined Behavior if no address is taken.
Otherwise, like in your case the value of stvar would be indeterminate. It's value can be arbitrary, it may even change between accesses.
Always initialize local variables.
Note that variables with static storage (globals and static) are zero initialized if not initialized explicitly.

The external (global) variables in C

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.

What will happen in C if the passing parameter is a constant value

Suppose I have a main function as below:
void main()
{ int *p;
p = foo(31);
printf(ā€œ%dā€, (*p)+2);
bar(7); /* Body of function bar() not shown */
printf(ā€œ%dā€, (*p)+4);
}
int *foo(int x)
{
return &x;
}
Assuming the function bar() that compiles correctly, why the second result of the printf is 11 if the body of bar() does not write to its incoming arguments space.
More specifically, my question is why the incoming argument value of bar() which is 7 replaces the value 31?
What's more, when the main function pass the value 31 into foo(), how does the value 31 passed? By register? or the compiler creates a temporary variable to pass 31? And why the incoming argument of foo() and bar() share the same position in the memory
Function parameters are its local variables. So in this function definition
int *foo(int x)
{
return &x;
}
there is returned a pointer to a local variable.
As result the program has undefined behavior.
You can imagine the function definition and its call the following way
p = foo(31);
int *foo( /* int x */ )
{
int x = 31;
return &x;
}
The variable x will not be alive after exiting the function. Thus the pointer has an invalid value that is a value that does not point to an actual object. The memory allocated for the parameter of the function foo can be overwritten by a call of other function as for example by a call of the function printf..
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )
and function foo should be declared before its usage. Otherwise the compiler can issue a message that either there is used incompatible types or it can not find the corresponding function.
The function foo receives a copy of the input parameter value in its local variable x. What foo sees does not depend on whether the argument to the function is constant or not.
The vatiable x is located on the stack and is freed when foo returns. So foo returns an address to a location in the stack. Returning a pointer to a local variable is an invitation for all kinds of problems.
In this case that same location most probably gets reused when bar is called.

Correct Return Values between normal and optimized builds

In slides 137-140 of this presentation, it was mentioned that bar() and maybe even foo() was compiled as inline functions for this sample program, resulting in the printout of a being 42 in normal builds even though it should technically be garbage. Do you happen to know why is the output garbage as expected when the optimizer kicks in?
I've included the source code
#include <stdio.h>
void foo(void)
{
int a;
printf("%d\n", a);
}
void bar(void)
{
int a = 42;
}
int main(void)
{
bar();
foo();
return 0;
}
and the command prompt printout for reference.
$ cc foo.c && ./a.out
42
$ cc -O foo.c && ./a.out
1606415608
Just an educated guess:
In the non-optimized case the compiler reserves a space for the a variable in bar() and initializes it to 42. Then, when foo() is called, it uses the same space for the uninitialized a and prints out 42.
When it's optimized, the initialization of a in bar() is optimized away, because it's not used. Probably, even the call to bar() is eliminated. So, as expected, foo() prints out garbage, that is whatever happens to be in that memory slot (or register) at the time.
a is uninitialised in the first function, which means you can't expect it to have any particular value. So compiler behaviour is correct in both cases (that you get 42 without optimisations is just a coincidence).

Resources