Do automatic variables have lifetime equal to that of a static variable (within the same block)?

I know that it's a silly question to ask, but please indulge me for a bit.

What do I know?

  • Scope of a variable x is basically the block within which x was defined. If x belongs to the automatic storage class then, it can only be used within the block where it was declared (which is precisely the scope of x).

  • Lifetime of a variable x is basically the time period during which x is allowed to live in the memory. And if x is an automatic variable then, by default it'll be killed as soon as it's scope is executed.

So, why do I have this question? It is because of the following code I accidentally conjured.

#include<stdio.h>
void scratch(void);
int main(void)
{
        for(int i = 0; i < 5; i++)
                scratch();
        return 0;
}
void scratch(void)
{
        static int static_var = 0;
        int auto_var1, auto_var2 = 0;
        printf("[info] 'static' variable = %d | 'auto' variable 1 = %d | 'auto' variable 2 = %d\n", static_var++, auto_var1++, auto_var2);
}

Output:

[info] 'static' variable = 0 | 'auto' variable 1 = 0 | 'auto' variable 2 = 0
[info] 'static' variable = 1 | 'auto' variable 1 = 1 | 'auto' variable 2 = 0
[info] 'static' variable = 2 | 'auto' variable 1 = 2 | 'auto' variable 2 = 0
[info] 'static' variable = 3 | 'auto' variable 1 = 3 | 'auto' variable 2 = 0
[info] 'static' variable = 4 | 'auto' variable 1 = 4 | 'auto' variable 2 = 0

The static variable, static_var does it's job perfectly well. However, notice the behavior of both automatic variables : auto_var1 & auto_var2. According to my understanding of automatic variables, both auto_var1 & auto_var2 should have printed 0 in each iteration, because their lifetime should have ended the moment scratch() returned to main(). But looks like these guys are living a long life. So my question is why? Does this mean that an automatic variable also has a lifetime equal to that of static variable in the same block? OR is it a compiler based issue?

Note : The above code was compiled via gcc version 7.2.0 on Ubuntu 17. Also, a request to everyone who attempts to answer this question : kindly stick to C for answering.

Do automatic variables have lifetime equal to that of a static variable (within the same block)?

Short answer - No, an object with automatic storage duration is limited to the block within which it is declared. An object with static storage duration remains valid for the life of the program. See C11 Standard - 6.2.4 Storage durations of objects

Now within the same block, from the standpoint of either object, both remain valid for the life of the block. The one with automatic storage duration will simply cease to be accessible after leaving the block while the one with static storage duration can be accessed elsewhere.

Difference between automatic (auto) and static variables in a C , What are automatic variables and static variables, what are the differences between them? the scope, lifetime, default value and memory segment of the variables. A static variable does not create a new each time and does not are declared i.e. static variable can be accessible within the same block. Static variable’s scope is also local to that function in which they are declared i.e. static variable can be accessible within the same block. Automatic variable’s life time is local (limited), automatic variables exit till the function execution time, when program’s execution leaves the function execution, variables are destroyed.

First variable is not initialized, you are printing garbage there.

int auto_var1, auto_var2 = 0;

Change this to initialize both, they'll both print 0 then.

int auto_var1 = 0, auto_var2 = 0;

Static variable, In computer programming, a static variable is a variable that has been allocated " statically", meaning that its lifetime (or "extent") is the entire run of the program. This is in contrast to shorter-lived automatic variables, whose storage is stack In many languages, global variables are always static, but in some languages they� Automatic : For a variable Automatic lifetime is , it is stack storage of variable (for multiple entry to a task, function or block, it will have stack storage) and its memory will be de-allocated once execution of that method or block is over. Default Lifetime of variable : 1. Class variable : Automatic 2. Method variable : Automatic 3. Local variable of loop : Automatic 4. Module or Program block variable : Static 5. Variable declared in initial of always block : Static I am explaining

The other answers tell you what you should do according to the C standard, I'll explain why it happens to work as it does.

In order to keep track of where functions should return and the values of their automatic variables, most platforms define a data structure called the stack, which may be grown or shrunk at one end. When a function f calls another function g, first a return address is pushed onto the stack and then g's automatic variables are created on the stack. When g returns, it deallocates its automatic variables and pops the return address from the stack and jumps to it, returning the stack to its state before the function call.

In your scratch function, auto_var1 is not initialised, so when the variable is created, nothing is written to it; it contains whatever happened to appear in that place in memory. The first time scratch was called, it happened to contain zero, so it was incremented to 1, and then the variable was destroyed. In subsequent calls, however, the stack layout is exactly the same as the first time scratch was called and so auto_var1 was allocated in the same place where it was before. Since the variable is still not initialised, the value is incremented again, and the variable appears to behave as if it was static.

Now, it's only by sheer luck that this works this way: it's because the stack layout is exactly the same in each call. If for example you had a call mainscratch and then mainfunc → scratch, this would no longer be the case. And even the above explanation is still somewhat simplified; for example, the compiler may choose to keep a variable in a CPU register instead of the stack, and reuse the register between function calls, so even keeping the call graph the same does not guarantee it working this way.

Even aside from all that, the code still exhibits undefined behaviour according to the C standard. The compiler is not guaranteed to preserve this behaviour in different circumstances, and it is not portable to different architectures; on some, like Itanium, the code may outright crash. Uninitialised memory is not even guaranteed to be 'stable': reading the same address more than once may yield different values each time.

Moral of the story: initialise your variables before reading them.

Automatic variable, In computer programming, an automatic variable is a local variable which is allocated and deallocated automatically when program flow enters and leaves the variable's scope. The scope is the lexical context, particularly the function or block in which a variable is defined. Automatic local variables are normally allocated in the stack frame of the� Variables declared in an automatic task, function, or block are local in scope, default to the lifetime of the call or block, and are initialized on each entry to the call or block. In other word, Automatic task/function variables cannot be accessed by hierarchical references.

The value of auto_var1 shows undefined behavior where it seems the variable keeps its value between function calls and gets incremented, just as the static variable does.

If you are running on Intel then this can be explained as follows:

The for loop does not change the stack and each time it calls function scratch() it modifies the stack in the same way by pushing return address, saving registers and then incrementing the stack pointer to create room for the local variables int auto_var1 and auto_var2. The second one is initialized to zero, the first one is not initialized, so the value in that memory location (variable) is the same as from the previous function call. The memory location gets incremented and the function returns. The next iteration increments it again and again.

The only point to notice is that in one or another way, the memory location was zero on the first iteration. This is a coincidence.

Visibility Scope and Lifetime of Variables - Variables, Therefore, the lifetime of a static variable is equal to the lifetime of the program. Here the scope of such a variable is limited to the block in which it is declared. For a static local variable, the allocation is static (the lifetime is the entire program execution), not automatic, but it is only in scope during the execution of the function. In specific programming languages C, C++ (Called automatic variables.) All variables declared within a block of code are automatic

[PDF] Chapter 5 Names, Bindings, Type Checking, and Scopes, Type: to design, must consider scope, lifetime, type checking, Names in most programming languages have the same form: a letter followed variables (the first appearance of the variable in the program.) • Both explicit and implicit declarations create static bindings to types. long as to execute equivalent machine code. Within a single compilation unit, static variables are initialized in the same order as they are defined in the source (this is called Ordered Dynamic Initialization). Across compilation units, however, the order is undefined: you don’t know if a static variable defined in a.cpp will be initialized before or after one in b.cpp .

Functions 2: Void (NonValue-Returning) Functions, Void function: does not have return type; Uses keyword void in function header constants //initialize global variables int main() { //initialize automatic variables int mm, even if function (or block) has an identifier with same name--by using scope variables declared within block are local to block; Scope of static variable� A variable declared within a block can only be accessed within that block. For example, local_d has block scope determined by the function-block for f and cannot be accessed outside that function. The variable ptr also has function-block scope limited to the main function. Note also that the local static, local_s, has block scope even though it

Storage classes (C++), Variables defined within a block have automatic storage unless otherwise When you declare a variable in a function, the static keyword specifies that instance member because the function does not have an implicit this pointer. words, at block scope thread_local is equivalent to thread_local static . In computer programming, a static variable is a variable that has been allocated "statically", meaning that its lifetime (or "extent") is the entire run of the program. This is in contrast to shorter-lived automatic variables, whose storage is stack allocated and deallocated on the call stack; and in contrast to objects, whose storage is dynamically allocated and deallocated in heap memory.

Comments
  • Undefined behavior.
  • if the static variable is destroyed after going out of the function then how can its value be retained the next time you call the function?
  • @phuclv, for static variables I believe that, they live for as long as the program exists. However they can only be used within their scope. And because they've a long life, therefore they're able to retain their values beyond their scope.
  • The value of the uninitialized variable auto_var1 is indeterminate, and using an indeterminate value results in undefined behaviour in C.
  • Considering the fact that an automatic variable's scope is also it's lifetime, how can one describe the ability of 'auto_var1' to retain it's value outside of it's lifetime? Or should I simply consider it as an undefined behaviour, as mentioned by @jxh?
  • auto_var1 can never retain is value outside its lifetime In a way that is legal to access it. The memory is released for reuse. Whether it has been overwritten yet or not is irrelevant -- you cannot access a variable outside its lifetime for that reason - no guarantee - invokes Undefined Behavior. "If an object is referred to outside of its lifetime, the behavior is undefined." (6.2.4(p2))
  • Okay. Now I get it. The reason, why auto_var1 was able to retain it's value even past it's life was only because there was no overwriting performed at it's memory location. So, this brings me to the question, shouldn't auto_var1 have been reallocated with new memory location every time scratch() gets called? Why reallocate it with the same memory location?
  • YEP!!! Bingo... The value is still there -- but you can't legally access it -- no guarantee it will be there. So we treat every variable that goes out of scope as untouchable...
  • @Argon - the last piece of the puzzle you are missing is that every time scratch() is called, a separate Function Stack is created, and all local variables are declared within that block of memory. When the function returns, the function stack is released for re-use. So every call to scratch() is a new and separate function stack setup (now does that mean the compiler cannot be smart enough to optimize that somehow to minimize system resources -- of course it can -- but how and whether the compiler optimizes some aspects of the call isn't something the standard allows you to rely on.)
  • Agreed. However, what can you say about their lifetime?
  • Thankyou for adding this perspective to the picture. Helped me to shape my entire thought process.