How static veriable is working

Dear All

void setup() {
  Serial.begin(9600);
  Serial.println(fun());
  Serial.println(fun());
  Serial.println(fun());
}

void loop() {

}

int fun() {
  static int count = 0;
  count ++;
  return count;
}

The above program output is

1

2

3

But always we called fun() function then the count variable should be zero ( static int count = 0;)

But it keeping previous value

???????

This is what 'static' means.

The value of count is kept between function runs.

When the variable is declared as static, it is allocated at the program beginning and deallocated at the program ends. It is initialized to 0 by default if another value is not specified and its visibility is only in scope where it was defined.

In your case the count exists after the fun() ends and it is keeping its value till the next run of fun(). The variable is initialized at the program start and Initialization statement is "ignored" during function execution. The definition has an impact just to visibility, it is not reachable outside of fun().

Dear Budvar10

Thanks for the reply

Can you please explain it more, how it ignore by the processor in point of view of micro controller architecture

Thanks in advance

It has nothing to do with the microcontroller architecture, it's the C language.

A static variable is like a global variable, in that it keeps it's value throughout the course of the sketch running - but like a local variable, it is only visible in the function that called it, so you don't have to worry about the same name being used somewhere else.

The machine code that gets uploaded tells it to do the initialization of that variable along with the global variables at the very start, not when the function is called, so there's no ignoring at the microcontroller level. The details of how a compiler transforms C code into machine code is very complicated, and most of it isn't that relevant to writing the C code.

Ignore what? If you want to start count from 0 each time the fun() is executed, only assignment of 0 out of declaration is needed. But the purpose of static variable is to keep its value outside of function. Static have no sense then because it is not visible/usable from outside and each time it starts from 0. It is better to ommit 'static' keyword and make it local so the lifetime will be only within the function and it free the memory immediately after the function ends.

static int count = 0;
static int count; // same as previous - static is initialized to 0 by default
...
static int count; 
  count = 0;  // it will be executed on each run so every time it starts from 0
...
int count = 0; // local - do the same job and it doesn't spend a memory while the program is out of function

As DrAzzy wrote, static variable is similar to global but with limited access. Compiler create the prologue code invisible for the user and there is also a loop for init with zero for all global and static variables. Both have reserved memory space during whole program run. The static variable is initialized in prologue even it looks like at the first function run from the C code view.

Refer to the C++ language specification.

This

static int count = 0;

is NOT a declaration and an assignment - it is a declaration and an initializer. They are not the same thing. Formally, they are different productions in the language grammar. Specifically, this is an example of a brace-or-equal-initializer (§A.7, p1224), whereas an assignment is an assignment-expression (§A.4, p1218)

§8.5: A declarator can specify an initial value for the identifier being declared. The identifier designates a variable being initialized. The process of initialization described in the remainder of 8.5 applies also to initializations specified by other syntactic contexts, such as the initialization of function parameters with argument expressions (5.2.2) or the initialization of return values (6.6.3).

Initializers are covered by different semantics to assignment statements:

§8.5 ¶2 Except for objects declared with the constexpr specifier, for which see 7.1.5, an initializer in the definition of a variable can consist of arbitrary expressions involving literals and previously declared variables and functions, regardless of the variable’s storage duration.

The specification has to lay this out explicity: it’s not covered by the assignment statement rules because an initializer is not an assignment.

With respect to static variables:

§8.5 ¶10 Note: Every object of static storage duration is zero-initialized at program startup before any other initialization takes place. In some cases, additional initialization is done later.

And - there’s your answer. That’s why. That’s what’s going on. It’s in the language specification - it’s what a C++ compiler is supposed to do.

Budvar10:
The static variable is initialized in prologue even it looks like at the first function run from the C code view.

That is not necessarily true. If a static variable is initialized using e.g. digitalRead, it will (also) be initialized in the function (wasting memory and cpu cycles in the process :wink: )
I don’t know the C spec, but the last part of the last quote in reply #6 confirms this.

Sample code

void loop()
{
  static byte buttonState = digitalRead(2);
  fa: 80 91 01 01 lds r24, 0x0101
  fe: 81 11       cpse r24, r1
 100: 08 c0       rjmp .+16     ; 0x112 <loop+0x18>
 102: 82 e0       ldi r24, 0x02 ; 2
 104: 0e 94 ec 00 call 0x1d8 ; 0x1d8 <digitalRead>
 108: 80 93 00 01 sts 0x0100, r24
 10c: 81 e0       ldi r24, 0x01 ; 1
 10e: 80 93 01 01 sts 0x0101, r24
 112: 08 95       ret

I meant zero init. It is at beginning of program.

Dear All,

I studied about static variable, how it runs in side the micro controller

What i got is, in side the CPU of every micro controller have a register called Accumulator (A) and some MCU's it is called working register (W)

After calculation get done the result can be transferred to variable or working register

Example x = 12

decf x,f // decrements from x then the result send to the x then x = 11 ( f mean file hear x )

in the static variable y

decf y,w // In this case decrements from y but result put to the w so y does not change

I am assuming this is how statics variables are working inside the micro controller

Hoped you all advice more thanks in advance

Static variables are something that belong to the language (I only know C and a bit of assembly); I don't know if other high-level languages (e.g. Pascal) know about them.

What makes it static is that the compiler knows that it should not touch (or forget) the variable's memory location outside a function.

There are basically 2 groups of locations in memory; the heap and the stack. All global and static variables go on the heap and all local variables go on the stack. When you call a function, the return address goes on the stack, variables that you pass go on the stack and local variables go on the stack.

[edit] Note that these are not physical groups. It's just how the compiler uses it in the available memory. [/edit]

The heap starts at the one side of the static (corrected) memory and the stack starts at the other side. The 328P micro has 2k memory for variables (we forget about the registers). It starts at location 0x100 and ends at 0x8FF (see figure 8-3 in the datasheet).

You can print the address location of variables in memory

char txBuffer[64];
byte globalVar1;
byte globalVar2;

void setup()
{
  byte localVar1;

  Serial.begin(115200);

  sprintf(txBuffer, "address of globalVar1 = %p", &globalVar1);
  Serial.println(txBuffer);

  sprintf(txBuffer, "address of globalVar2 = %p", &globalVar2);
  Serial.println(txBuffer);

  sprintf(txBuffer, "address of localVar1 = %p", &localVar1);
  Serial.println(txBuffer);
}

void loop()
{
}

The output:

address of globalVar1 = 0x1d6
address of globalVar2 = 0x1d5
address of localVar1 = 0x8f9

Note the difference between the two globalVars and the localVar; the first two are on the heap and the latter one is on the stack.

Next we can add two functions that are called from setup() and print the address of a non-static local variable.

char txBuffer[64];
byte globalVar1;
byte globalVar2;

void setup()
{
  byte localVar1;

  Serial.begin(115200);

  sprintf(txBuffer, "address of globalVar1 = %p", &globalVar1);
  Serial.println(txBuffer);

  sprintf(txBuffer, "address of globalVar2 = %p", &globalVar2);
  Serial.println(txBuffer);

  sprintf(txBuffer, "address of localVar1 = %p", &localVar1);
  Serial.println(txBuffer);

  func1();
  func2();
}

void func2()
{
  byte localVar22;
  
  sprintf(txBuffer, "address of localVar22 = %p", &localVar22);
  Serial.println(txBuffer);
}

void func1()
{
  byte localVar33;
  
  sprintf(txBuffer, "address of localVar33 = %p", &localVar33);
  Serial.println(txBuffer);
}

void loop()
{
}

The result shows that the two new local variables are located on the stack and both have the same address.

address of globalVar1 = 0x1a3
address of globalVar2 = 0x1a2
address of localVar1 = 0x8f7
address of localVar33 = 0x8e0
address of localVar22 = 0x8e0

Now change the localVars in func1 and func2 to static variables and see what happens.

char txBuffer[64];
byte globalVar1;
byte globalVar2;


void setup()
{
  byte localVar1;

  Serial.begin(115200);

  sprintf(txBuffer, "address of globalVar1 = %p", &globalVar1);
  Serial.println(txBuffer);

  sprintf(txBuffer, "address of globalVar2 = %p", &globalVar2);
  Serial.println(txBuffer);

  sprintf(txBuffer, "address of localVar1 = %p", &localVar1);
  Serial.println(txBuffer);

  func1();
  func2();
  
}

void func2()
{
  static byte localVar22;
  
  sprintf(txBuffer, "address of localVar22 = %p", &localVar22);
  Serial.println(txBuffer);
}

void func1()
{
  static byte localVar33;
  
  sprintf(txBuffer, "address of localVar33 = %p", &localVar33);
  Serial.println(txBuffer);
}

void loop()
{
}

Each variable now has a different address and they are located in a different area in memory (same area as the globals).

address of globalVar1 = 0x1a5
address of globalVar2 = 0x1a4
address of localVar1 = 0x8f7
address of localVar33 = 0x1a2
address of localVar22 = 0x1a3

Hope that this clarifies it a bit.

PA3040: I studied about static variable, how it runs in side the micro controller

What i got is, in side the CPU of every micro controller have a register called Accumulator (A) and some MCU's it is called working register (W)

After calculation get done the result can be transferred to variable or working register

I don't know why this level of detail matters to you - you are holding the stick by the wrong end. The C++ language specification defines how static variables behave. It is the job of the compiler to generate machine code that correctly operates as the language specifies. What code it actually generates is irrelevant.

What you are doing is like trying to understand what a resistor does by examining the chemical composition of a resistor. I mean: sure, a resistor is made of chemicals and they react to electrical fields in a particular way. But pulling out a microscope examining the contents of any particular resistor isn't really going to tell you much about resistors in general, about what they are for, what purpose they have in electrical circuits.

Thanks for the reply

can't we able to create a static variable from assembly

Thanks in advance

You can; simply only use a memory location/register in one specific function and not in any other one.