I learned some C and came across an explanation for static variables.
They showed this code:
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
I can't understand why calling the function twice is fine, because the line
static int count = 0;
actually runs twice...
I can't understand how is that possible...
Can you actually declare it twice or does the compiler just ignore it the second time?
This (statics/globals) is where an initializing definition is really different from an uninitialized definition followed by an assignment.
Historically, the former even used to have different syntax (int count /*no '=' here*/ 0;).
When you do:
int fun() {
static int count = 0;
//...
}
then except for the different scopes (but not lifetimes) of count, it's equivalent to:
static int count = 0; //wider scope, same lifetime
int fun() {
//...
}
In both cases, the static variable becomes initialized at load time, typically en-masse with other statics and globals in the executable.
static variables are initialized on program startup, not every time the function is called.
... because the line static int count = 0; actually runs twice.
No. Just once, right before main() is called.
Related
So here is an example:
#include <stdio.h>
int main(void) {
static int i=0;
printf("%d",i);
static int i=0;
printf("%d",i);
return 0;
}
This gives me an error:
error: redefinition of 'i'
Now here is another Example :
#include <stdio.h>
void increment(void) {
static unsigned int counter = 0;
counter++;
printf("%d ", counter);
}
int main(void) {
for (int i = 0; i < 5; i++) {
increment();
}
return 0;
}
This gives the output :
1 2 3 4 5
Why does this happen ?
In the second example by calling the function aren't we redeclaring it? And shouldn't the output be 1 1 1 1 1 ?
In the second example by calling the function aren't we redeclaring it?
No, we aren't: We are declaring i in a different scope; specifically, in the body of a different function. You can only define a variable once within a given scope (ignoring sub-scopes); but you can define a variable of the same name in different scopes:
int i; // global scope
void foo()
{
int i; // scope - body of foo
{
int i; // a sub-scope of the body of foo
}
}
int main()
{
int i; // a different scope - body of main, not body of foo
}
and the "closest" definition to a command is the one which will be relevant; it will "shadow" the other variables of the same name which might otherwise be usable in that scope.
Of course, it's not a good idea to define many variables with the same name which may shadow each other - it's confusing and their names will likely not be meaningful. People often use a one-letter variable for a loop counter: i, j, k etc. - but then you would tend avoid using i for something more long-lasting.
1 2 3 4 5...
Why does this happen ?
Because within the increment() function, the counter is a static unsigned int, meaning it has static storage duration - it is only initialized once, and maintains its value between invocations of the function.
I had this assignment at school, wherein I had to find the output of the following C code, and also, to explain the output.
#include<stdio.h>
int i;
void fun1(void);
void fun2(void);
int main()
{
fun1();
fun2();
return 0;
}
void fun1(){
i=20;
printf("%d\t",i);
}
void fun2(){
int i=50;
printf("%d",i);
}
The output is 20 50
Because in fun1() the Global Variable 'i' is assigned to 20 and printed. And in fun2() the variable 'i' is a Local Variable, which is declared and initialized to 50, which is then printed.
I have this following question out of curiosity, how do I use the global variable 'i', in fun2()?
A simple solution would be to simply change the name and avoid the whole thing. But my curiosity is due to Java, where there is a keyword "this" to access class variable instead of a local variable.
so is there any way to do that in C?
The only way is to hide the declaration of the local variable in a code block.
For example
#include <stdio.h>
int i = 10;
void fun2( void )
{
int i = 20;
printf("local i = %d\n",i);
{
extern int i;
printf( "global i = %d\n",i);
}
}
int main(void)
{
fun2();
}
The program output is
local i = 20
global i = 10
There is no way to access a global parameter inside a function that has a local variable with the same name. It is usually bad practice to create such local variables in C though, as you saw, it is not prohibited.
In C++ you can solve it using namespaces but there is no equivalent in C.
The best way is to pass parameters to the function
void fun2(int fromExternalWorld){
int i=50;
printf("%d ",fromExternalWorld);
printf("%d\n",i);
}
int main(void)
{
fun2(i);
}
Otherwise is not possible to have two symbols with same name visible in the same scope.
You could cheat and create a pointer to the global i before declaring the local i:
void fun2( void )
{
int *ip = &i; // get address of global i
int i = 50; // local i ”shadows" global i
printf( "local i = %d, global i = %d\n", i, *ip );
}
EDIT
Seeing as this answer got accepted, I must emphasize that you should never write code like this. This is a band-aid around poor programming practice.
Avoid globals where possible, and where not possible use a naming convention that clearly marks them as global and is unlikely to be shadowed (such as prefixing with a g_ or something similar).
I can't tell you how many hours I've wasted chasing down issues that were due to a naming collision like this.
My goal is to add (without modifying any of the existing code) a function retrieve() which returns the current value of the counter.
#include <stdio.h>
void increment(void){
static unsigned int counter = 0;
counter++;
printf("%d\n", counter);
}
int main(void){
for (int i = 0; i < 5; i++){
increment();
}
printf("counter = %d\n", retrieve());
return 0;
}
However, everything I try is running into a scope issue. Namely that counter has not yet been instantiated yet so the compiler considers it to be an undefined name. I've tried adding a function
int retrieve(void){
return counter;
}
between increment and main and also within both increment and main themselves. My understanding of the static keyword is that once the variable is instantiated it will persist beyond the block it is defined in for the length of the program execution. So I think the issue I'm running into is that the variable is not yet instantiated. Any help would be great.
Scope and lifetime are two different things, and they're partly independent.
Scope is the region of program text in which an identifier is visible.
Lifetime (or storage duration) is the duration during program execution in which an object exists.
The object named counter, because it's defined with static, has static storage duration, which means that it exists during the entire execution of the program. But the identifier counter has block scope, which means that the name is visible only from its declaration to the } that terminates the innermost block in which it's declared. (In this case, that block happens to be the outermost block of a function definition.)
you need to move counter into global scope
#include <stdio.h>
static unsigned int counter = 0; <<<=========
void increment(void){
counter++;
printf("%d\n", counter);
}
int retrieve(void){
return counter;
}
int main(void){
for (int i = 0; i < 5; i++){
increment();
}
printf("counter = %d\n", retrieve());
return 0;
}
accepted best practice is to indicate in the name that its global
unsigned int COUNTER = 0;
or
unsigned int g_counter = 0;
I just want to understand the difference in RAM allocation.
Why if i define a variable before function i have a RAM overflow and when i define it inside a function it is ok?
For example:
/*RAM OK*/
void Record(int16_t* current, int i,int n)
{
float Arr[NLOG2] = {0};
for(i=0;i<n;i++)
Arr[i]=current[i*5];
}
/*RAM OVERFLOW*/
static float Arr[NLOG2] = {0};
void Record(int16_t* current, int i,int n)
{
for(i=0;i<n;i++)
Arr[i]=current[i*5];
}
This is the message:
unable to allocate space for sections/blocks with a total estimated
minimum size of 0x330b bytes (max align 0x8) in
<[0x200000c8-0x200031ff]> (total uncommitted space 0x2f38).
The difference is that in the first case, Arr is declared on the stack; until the function is called, that array doesn't exist. The generated binary contains code for creating the array, but the array itself isn't in the binary.
In the second case, however, Arr is declared outside of any function (aka at file scope). Therefore, it always exists, and is stored in the binary. Because you appear to be working on an embedded platform, this otherwise insignificant difference causes your "RAM overflow" error.
In the 2nd case, the array is allocated when the application starts. It remains in the memory until the app quits.
In the 1st case, the array is only allocated when function void Record(int16_t* current, int i,int n) is called. The array is gone after the function finishes its execution.
static keyword doesn't have any impact if you have only a single compilation unit (.o file).
Global variables (not static) are there when you create the .o file available to the linker for use in other files. Therefore, if you have two files like this, you get name collision on a:
a.c:
#include <stdio.h>
int a;
int compute(void);
int main()
{
a = 1;
printf("%d %d\n", a, compute());
return 0;
}
b.c:
int a;
int compute(void)
{
a = 0;
return a;
}
because the linker doesn't know which of the global as to use.
However, when you define static globals, you are telling the compiler to keep the variable only for that file and don't let the linker know about it. So if you add static (in the definition of a) to the two sample codes I wrote, you won't get name collisions simply because the linker doesn't even know there is an a in either of the files:
a.c:
#include <stdio.h>
static int a;
int compute(void);
int main()
{
a = 1;
printf("%d %d\n", a, compute());
return 0;
}
b.c:
static int a;
int compute(void)
{
a = 0;
return a;
}
This means that each file works with its own a without knowing about the other ones.
I was looking for a function to do some audio effect, and I found one written in C.
Inside this function, some variables are declared as Static. I am confused, I thought Static means these variables are not visibles to other files. But since they are declared inside inside a function, they are already not visible to other files.
What am I missing ?
static inside a function means that it will hold its value the next time the function is called.
For example,
int foo() {
static int i = 0;
printf("%d\n", i);
i++;
}
int main() {
foo(); // Prints 0
foo(); // Prints 1
}