Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining a variable and its static equivalent in the same function

I don't understand how the following code works:

#include "stdio.h"

int main(void) {
  int i = 3;
  while(i--) {
    static int i = 100;
    i--,
    printf("%d\n", i);
  }
  return 0;
}

The code compiled with either Clang or GCC prints the following output:

99
98
97

Can someone explain to me what happens here? It looks like two operations are achieved in a single instruction and more than once. Is it undefined behavior? I observe the same behavior in C++.

like image 385
Xatyrian Avatar asked Jan 31 '18 10:01

Xatyrian


People also ask

What is the equivalent of static in Python?

Python doesn't have static variables but you can fake it by defining a callable class object and then using it as a function.

What are static variables and functions?

Static functions can be called directly by using class name. Static variables are initialized only once. Compiler persist the variable till the end of the program. Static variable can be defined inside or outside the function. They are local to the block.

What can I use instead of a static variable?

Yes, you can use Construct On First Use Idiom if it simplifies your problem. It's always better than global objects whose initialization depend on other global objects.

What is the static variable in function useful for?

Static variables have a property of preserving their value even after they are out of their scope! Hence, static variables preserve their previous value in their previous scope and are not initialized again in the new scope.


3 Answers

This is not undefined behavior.

#include "stdio.h"

int main(void) {
  int i = 3; //first i
  while(i--) {
    static int i = 100; //second i
    i--,
    printf("%d\n", i);
  }
  return 0;
}

In while loop body most local i (second i) is preferred. While checking condition in while loop it doesn't know what is there in body. So it has no problem choosing first i.

like image 67
Pranit Kothari Avatar answered Oct 19 '22 10:10

Pranit Kothari


Wikipedia says very prominent thing on this:

In computer programming, variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. At the level of identifiers (names, rather than variables), this is known as name masking. This outer variable is said to be shadowed by the inner variable, while the inner identifier is said to mask the outer identifier.

Now here inside the block it finds the static variable and works on it but the while condition decrements the i which is the one declared outside the block. The scope being different - it is no problem to use the correct value of i. This is legal C code but not necessarily a good way of writing things.

In fact doing this gcc -Wshadow progname.c gives

progname.c: In function 'main':
progname.c:7:20: warning: declaration of 'i' shadows a previous local [-Wshadow]
         static int i=2;
                    ^
progname.c:5:9: warning: shadowed declaration is here [-Wshadow]
     int i=2;
         ^

From standard §6.2.1p4

... If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.

like image 22
user2736738 Avatar answered Oct 19 '22 10:10

user2736738


Its possible to declare a same named variable inside a nested scope. The compiler sees them as different variables. It is very confusing but the variable you are accessing each time is the one declared in the inner most scope. Outside the while it is the int i = 3; and inside it is the static int i = 100;

#include "stdio.h"

int main(void) {
  int i = 3; // outer i
  while(i--) { // outer i
    static int i = 100; // inner i
    i--, // inner i
    printf("%d\n", i); // inner i
  }
  return 0;
}

If this was a function other than main, then the 2nd call to it would produce

96
95
94

and so on...

like image 2
CIsForCookies Avatar answered Oct 19 '22 08:10

CIsForCookies