-3

I'm attempting to run the following C code

#include <stdio.h>

void myFunc() {
    static int a;
    int b;
    a++;
    b = b + 2;
    printf("a:%d, b:%d\n",a,b);
}

int main(void)  {
    myFunc();
    myFunc();
    return 0;
}

The result I get when compiling on ubuntu with gcc version 5.4.0 20160609 is

a:1, b:2
a:2, b:4

I understand that a, being static, will be zero initialized, but it appears that non-static b is being zero initialized as well. Further, it looks like b is actually being converted to a static variable, since its value is retained for the second call to myFunc.

I'm assuming this has something to do with my compiler/OS because compiling with codepad online (using gcc 4.1.2) gives

a:1, b:2
a:2, b:2

which, while still zero-initializing b for some reason, does not retain the value of b for subsequent calls to myFunc.

1) Why is a non-static variable being zero-initialized? Am I just constantly getting lucky that the compiler assigned to it a memory block that was zero'd?

2) Why does gcc seem to convert b to a static variable in gcc 4 but not gcc 5?

EDIT:

To better illustrate this issue, if I add, say, 6 more calls to myFunc, the resulting output is:

a:1, b:2
a:2, b:4
a:3, b:6
a:4, b:8
a:5, b:10
a:6, b:12
a:7, b:14
a:8, b:16
keaek
  • 15
  • 1
  • 4
    Undefined behavior is undefined... – John3136 Dec 14 '16 at 23:34
  • 1
    Try adding another (different) function between your two calls to `myFunc()` and create new variables in that function... see what happens. But, like @John3136 said... – embedded_guy Dec 14 '16 at 23:40
  • 1
    @Al Kenny: How do you tell the difference between a genuinely zero-initialized variable and a garbage variable that just happens to have garbage value 0? And how do you tell a variable that genuinely retains its value between calls (static) and a garbage variable that just happens to match its previous value purely accidentally? – AnT stands with Russia Dec 14 '16 at 23:44
  • 1
    "Why is a non-static variable being zero-initialized?" this is not certain. The compiler sees code like `int b; b = b + 2; printf("b:%d\n",b);` and can replace that with `puts("b:2"):` or `destroy_hard_drive()`. Either are OK as it is _undefined behavior_. – chux - Reinstate Monica Dec 14 '16 at 23:51
  • @embedded_guy: I've added the following function to the code: `void testFunc() { static int c; int d; c++; d = d + 2; printf("c:%d, d:%d\n",c,d); }` and changed the code in main to be ` myFunc(); testFunc(); myFunc(); testFunc(); myFunc(); testFunc(); myFunc(); testFunc();` .... what results is: `a:1, b:2` `c:1, d:4` `a:2, b:6` `c:2, d:8` `a:3, b:10` `c:3, d:12` `....` – keaek Dec 15 '16 at 00:40
  • @AnT: as shown in my reply to embedded_guy, it sure seems like there's some carry over between calls to the myFunc. Indeed, it would appear that `b` and `d` are accessing the same location in memory each time myFunc and testFunc run. The odds of different locations in memory having exactly these values seems pretty slim. What might be happening here? – keaek Dec 15 '16 at 00:50
  • 1
    The memory location is on the stack. Since you're calling them from the same parent function, you're using the same stack memory each time, and nothing is overwriting it between the calls. – Barmar Dec 15 '16 at 00:58
  • @keaek: Well, yes, that is exactly what's happening. The fact that the memory location in question retained its value is not surprising since the two calls immediately follow each other. But inster something other call between them and it will all fall apart. – AnT stands with Russia Dec 15 '16 at 01:19
  • What did you expect to happen instead, and why? – M.M Dec 15 '16 at 01:24
  • @M.M I honestly expected to get pure and simple garbage from b and d each time either function ran. If I'm understanding everyone correctly here, what appears to be happening is that the same memory block on the stack is being allocated each time these functions are being called. "here you go, have location X" "ok, X is done, time to release it (without clearing it)" "oh, you want some memory as well? I guess I'll give you X too" – keaek Dec 15 '16 at 01:34

1 Answers1

3
  1. Your non-static variable b is not zero-initialized. In your experiment it just so happened that the indeterminate garbage value in b was zero. Zero is as garbage as any other value.

  2. Variable b is not "converted to static". It does not retain its value between calls. In your experiment it just so happened that the indeterminate garbage value of b in the second function invocation was the same as the last value from the first invocation. That value is as garbage as any other value.

While there are rather simple and deterministic underlying reasons for the "accidental" behavior you observed, it is as fragile as it gets. None of this will hold in real-life code.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Running myFunc several more times seems to show results that are counter to what you're saying though. If I modify the main block of code to call myFunc 8 times, I get the output: `a:1, b:2` `a:2, b:4` `a:3, b:6` `a:4, b:8` `a:5, b:10` `a:6, b:12` `a:7, b:14` `a:8, b:16` – keaek Dec 15 '16 at 00:54
  • @keaek Try calling some other function between the calls to `myFunc()`. The reason you're seeing that is because nothing else is using that part of the stack, so it still has what was left from the previous call. – Barmar Dec 15 '16 at 00:56
  • @Barmar That clears a few things up. If I add the function `void print_something() { printf("something\n"); }` and call it between calls to `myFunc()`, I get something like `a:1, b:2 something a:2, b:2 something a:3, b:2 something a:4, b:2 something a:5, b:2 something` – keaek Dec 15 '16 at 01:02
  • @keaek: It doesn't really "counter" it. It simply means that you are continuing to deliberately, succesfully (and meaninglessly) balance upturned Eiffel tower on its tip in ultra-clean laboratory conditions (no wind or sound). Just try calling someting else between your calls and it will all fall apart and come crashing down. – AnT stands with Russia Dec 15 '16 at 01:21