简体   繁体   中英

declaration of variables with same name as global,local and static

I have the following code snippet and I have to analyse what the output will be:

#include <stdio.h>

  void f(int d);

  int a = 1, b = 2, c = 3, d = 4;

  int main(){
    int a = 5, c = 6;
    f(a);
    f(b);
    f(c);
    printf("%d %d %d %d\n",a,b,c,d);
    return 0;
  }

  void f(int d){
    static int a = 0;
    a = a + 7;
    b = a + d;
    c++;
    d--;
    printf("%d %d %d %d\n",a,b,c,d);
  }

The output I've got is as follows:

7 12 4 4  
15 26 5 11  
21 27 6 5  
5 27 6 4  

This really baffled me. I noticed that in all 3 function calls the globally declared a suffers the assignment and that in the printf() from main() body the a declared in main() is printed. However, I am not sure about the behaviour of the rest of the variables. Is this undefined behaviour or it actually makes sense?

int a = 1, b = 2, c = 3, d = 4; ---> Global variables

int main(){
    int a = 5, c = 6;         ---> Shadows the global `a` and `c`

....

void f(int d){
    static int a = 0;         ---> local static variable visible only inside `f`

...

This is related to C's identifier scopes. The scope of a declaration is the region of the C program over which that declaration is visible. There are six scopes:

  • Top level identifiers: extends from the declaration point to the end of the source program file
  • Formal parameters in a function definiton: extends to the end of the function body
  • Formal parameters in function prototypes
  • Block (local) identifiers: extends up to the end of the block
  • Statement labels
  • Preprocessor macros

What happens in your program is known as overloading of names - a situation in which the same identifier may be associated to more than one program entity at a time. There are 5 overloading classes in C (aka namespaces):

  • Preprocessor macro names
  • Statement labels
  • Structure, union and enumeration tags
  • Component names
  • Other names

In C, declarations at the beginning of a block can hide declarations outside the block. For one declaration to hide another, the declared identifiers must be the same, must belong to the same overloading class, and must be declared in two distinct scopes, one of which contains the other.

With this in mind, in your code, local a and c hide global a and c in main() , and a in f() hides global a . All other references are manipulating the global variables.

 void f(int d){
     **static int a = 0;**
     a = a + 7;
     b = a + d;
     c++;
     d--;
     printf("%d %d %d %d\n",a,b,c,d);
   }

That's right you declared global int a and global void function f but also you have declared static variable a Whenever function has called, function is refering a variable of function. if you want to avoid this problem, you should make a pointer of global variable, and refering a pointed address's value global variable. As you know static variable is keep their last value until end of program.

each function's variable is exactly going to placed in "Stack" unless allocated by malloc. And global variable is "Heap". I am not sure but if you disassembly your program, static value a would go to stack and treated with PUSH and POP instruction.

In C/C++, the identifiers in a given scope shadow the identifiers in the outer scope from the point of declaration onwards .

The following example demonstrates this:

#include <stdio.h>

const char a[] = "a";

static const char b[] = "b";

void test(const char * arg)
{
   const char c[] = "c1";
   printf("1-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
   const char a[] = "a1";
   static const char b[] = "b1";
   // arg is present in this scope, we can't redeclare it
   printf("1+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
   {
      const char a[] = "a2";
      const char b[] = "b2";
      const char arg[] = "arg2";
      const char c[] = "c2";
      printf("2-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
      {
         static const char a[] = "a3";
         const char b[] = "b3";
         static char arg[] = "arg3";
         static const char c[] = "c3";
         printf("3. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
      }
      printf("2+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
   }
   printf("1++. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}

int main(void)
{
   test("arg");
   return 0;
}

Output:

1-. a=a b=b c=c1 arg=arg
1+. a=a1 b=b1 c=c1 arg=arg
2-. a=a2 b=b2 c=c2 arg=arg2
3. a=a3 b=b3 c=c3 arg=arg3
2+. a=a2 b=b2 c=c2 arg=arg2
1++. a=a1 b=b1 c=c1 arg=arg

This output actually makes sense.

In C/C++, the identifiers in a given scope are given preference over the identifiers in the outer scope. In this case in the function main, variables a and c will be used as local variables and rest b and d as global variables. Similarly, in the function void f(int d) , d is the passed parameter, a will be used as static whenever the function is called, b and c will be used as global variables. Hence the output will be calculated.

However you have shown the incorrect output. Correct output must be :

7 12 4 4 14 26 5 11 21 27 6 5 5 27 6 4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM