1
#include<stdio.h>

void foo(void)
{
    int a=42;
}

void boo(void)
{
    int a;
    printf("%d\n",a);
}

int main()
{
    foo();
    boo();
}

Why does boo print the value of a from foo? I read an explanation about the execution stack and activation frames but I do not understand it.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
user9679818
  • 103
  • 8
  • 2
    https://stackoverflow.com/a/4105123/1505939 – M.M Jul 13 '18 at 00:05
  • 5
    undefined behavior is undefined behavior. – Stargateur Jul 13 '18 at 00:07
  • 2
    In function `boo`, variable `a` is uninitialized. So it gets a random value. Is 42 not random enough for you? :-) – Steve Summit Jul 13 '18 at 00:09
  • @M.M thanks ı will be reading this now. – user9679818 Jul 13 '18 at 00:12
  • 1
    Local ("automatic" duration) variables are typically stored on the stack, which gets reused by each new function that's called. So function `boo` gets a stack frame on the part of the stack formerly occupied by function `foo`'s stack frame, and so uninitialized variables in function `boo` typically receive whatever random value was left there by function `foo`. Sometimes, that's even a "reasonable" looking value. In this case, since functions `foo` and `boo` both have exactly one local variable, their stack frame layouts end up being nearly identical. – Steve Summit Jul 13 '18 at 00:12
  • @SteveSummit https://www.slideshare.net/olvemaudal/deep-c/137-include_stdioh_cc_O_fooc here you can see , just go ahead and you will see that the same program is being complied in a different way and the result changes. what does cc -0 make so that the result changes ? – user9679818 Jul 13 '18 at 00:14
  • 2
    @user9679818: Undefined behaviour means any result is acceptable — and changes to options etc can change what's printed and its right both ways (or, more accurately, equally wrong both ways). Simply don't do it. Don't expect uninitialized variables to hold any specific value — the value can change at any time, for any reason. – Jonathan Leffler Jul 13 '18 at 00:16
  • @SteveSummit: I prefer to say it gets an *arbitrary* value rather than a random one. "Random" places too many (implicit) constraints on a novice's expectations. – Keith Thompson Jul 13 '18 at 00:17
  • @SteveSummit Thank you for answer this is enough for me to understand but guess it is better to read what M.M refer to . – user9679818 Jul 13 '18 at 00:17
  • 1
    @user - As the slides talk about "different results for other compilers", this is what my compiler displays: *"warning C4700: uninitialized local variable 'a' used"* and *"fatal error LNK1257: code generation failed"*. And no executable produced. – Bo Persson Jul 13 '18 at 00:18
  • @user9679818 Sorry, can't view that slide show, but that's okay. Why do you want to know why it changes? Does it matter? Do you need it not to change? Do you need to predict how it will change? Or is this just curiosity on your part? – Steve Summit Jul 13 '18 at 00:18
  • @SteveSummit this is just curiosity :) – user9679818 Jul 13 '18 at 00:24
  • 4
    @user9679818 Oftentimes curiosity is a fine thing, sometimes it's misplaced. On this issue it can go either way. For me, it's like asking, "Yesterday I ran a red light and nothing happened. Today I ran a red light and got hit by a red car. Why? And why didn't I get hit by a blue truck?" – Steve Summit Jul 13 '18 at 00:32
  • @user9679818 On the other hand, yes, if you can figure out precisely how the stack frames are arranged, and how they move around under different compilation options, you might learn a lot about assembly language and stack frame layout, and it might even be useful knowledge -- but I can't help you with it, because I haven't worried about assembly language or stack frame layouts for many years. – Steve Summit Jul 13 '18 at 00:32
  • @SteveSummit thanks for the answers :) same for those who answered this question. – user9679818 Jul 13 '18 at 00:41
  • @SteveSummit This makes tools like [Valgrind](http://valgrind.org) akin to ensuring that there's lots of red cars and blue trucks to hit you every time. – tadman Jul 13 '18 at 00:54
  • [42](https://en.wikipedia.org/wiki/42_(number)#The_Hitchhiker's_Guide_to_the_Galaxy) is the answer to the _Ultimate Question_. – chux - Reinstate Monica Jul 13 '18 at 01:14

1 Answers1

3

This is how your function is called(a).

                   stack
---------------------------------      call             return
---------------------------------
               |                |
earlier frame  | earlier frame  |
               |                |
---------------------------------
---------------------------------
               |                |                     (5) pop old %ebp to %ebp
               |----------------|
caller's frame | func arguments | (1) push args
               |----------------|
               | return address | (2) push ret-addr   (6) reset %esp here
---------------------------------
---------------------------------
               | old %ebp       | (3) push old %ebp   (4) reset %esp = %ebp
               |----------------|     reset %ebp here
               |                |
callee's frame | local variables|
               |                |
---------------------------------
---------------------------------

When a function returns, the data in its frame may be kept. So, in your case, boo() used the same frame with old data of foo().


(a) Nothing in the standard guarantees this, it's just the most likely explanation for your particular scenario.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Joy Allen
  • 402
  • 3
  • 8