views:

103

answers:

5

All,

Consider the following code:

void func(void)
{
    int a;
    printf ("%d", a);
}

int main(int argc, char **argv)
{
    int a = 3;
    func();
    printf("%d", a);
}

According to my understanding, the output should be:

<junk value><3>

Can anyone please confirm my understanding? My basic query is, does the compiler refer to the outer scope for a variable that has been declared but not defined?

Regards, darkie

+9  A: 

Your understanding is correct. func's a is initialized with stack trash.

Each time you say int a;, it will create a new variable, with no relation to similarly named variables from enclosing scopes or variables from other functions higher up the call-stack.

In your justification, you're confusing Scope and Extent. c uses lexical scoping, so while main's "extent" (or liftime) exists through the execution of func, it is an entirely different scope, so it refers to an entirely different variable.

Note that an "outer scope" is usually the braces outside of yours, with the outermost scope being file level.

int a; // global
void func(int a) {  // parameter
  int a;  // function local
  while (0) {
    int a;  // scoped in the 'while'
    if (true) { 
      int a;  // scoped in the 'if'
    }
  }
}

Each one of those 'a' variables shadows the other 'a's above it.

The exception (maybe the source of your confusion) being a variable declared extern int a;. This variable specifically refers to a variable from somewhere else (different translation unit). An external declaration may be used to get the behavior you were not expecting:

An external variable may also be declared inside a function. In this case you must use the extern keyword, otherwise the compiler will consider it a definition of a local variable, which has a different scope, lifetime and initial value. This declaration will only be visible inside the function.

The exceptions to the "stack trash" rule are that static and heap allocated variables are zero initialized (if I am not mistaken, this is enforced by the standard).

And also note that "garbage value" might be 3.

Stephen
His example doesn't have an enclosing scope!
Lucas
@Lucas, i didn't mean to infer that it did. Edited to clarify.
Stephen
@Stephen +1: Very complete answer. I didn't assume that you meant it did, but it was a little misleading considering his example.
Lucas
+1  A: 

Your predicted result is correct, but your reasoning not entirely. It would never refer to the variable a in the main function, since main is not in the outer scope of func. Even when when it would exist in the outer scope, it would be shadowed by the variable in the inner scope. Example:

int a = 3;
printf("%d", a);
{
    int a;
    printf ("%d", a);
}

would print <3> <junk value

Lucas
A: 

Both a variables have different scopes. The ouptut you imagine is correct.

pcent
A: 

In your case you neither have an outer scope or an inner scope: you have two local scopes that just last inside the blocks delimited by { and }.

So yes, in your case just the a defined inside func() will be used by the printf inside that function.

A similar situation in which you effectively have a global scope variable like

int a = 0;

int main(void)
{
  int a;
  printf("%d", a);
}

would produce the same junk result since the new declaration shadows the global one.

The compiler doesn't care wheter a variable has been initialized or not, just care about using the nearest declaration (nearest in the sense of scoping).

Jack
A: 

On my Solaris 9 box with gcc 3.4.2:

#include <stdio.h>

void func(void) 
{ 
    int a; 
    printf ("func:%d ", a); 
    a=9;
} 

int main(int argc, char **argv) 
{ 
    int a = 3; 
    while(a--)
        func(); 
    printf("main:%d\n", a); 
} 

output:

> ./a.out
func:-12719276 func:9 func:9 main:-1

The '9' comes from the previous incarnation of the function. Meaning on this system the function was mapped to exactly the same stack frame every time it was called, so it shows the 'leftover' garbage effect clearly. We created it ourselves.

jim mcnamara
This one of the reasons for 0xDEADBEEF being assigned to variables to locate problems like this - in debuggers it is very obvious when you see avariable with value = DEADBEEF that you have leftovers in your data.
jim mcnamara