Stack frame structure for a function with a sub scope - c

Following is the code, that I took as reference to understand how a sub scope (or) dummy scope (just {}) present within the function, impacts the structure of the stack frame.
#include <stdio.h>
int main()
{
int main_scope=0; /*Scope and life time of the variable is throughout main*/
{
//From below two statements I assume that there
//is no seperate "stack frame" created for just
//braces {}.So we are free access (scope exists) and
//modify (lifetime exists) the variable "main_scope"
//anywhere within main
main_scope++;
printf("main_scope++:(%d)\n",main_scope);
//I expected this statement to throw an error saying
//"Multiple definition for "main_scope".But it isn't????
int main_scope=2;
printf("Value of redefined main_scope:(%d)\n",main_scope);
}
printf("Finally main_scope in %s:(%d)\n",__FUNCTION__,main_scope);
return 0;
}
Sample output
main_scope++:(1)
Value of redefined main_scope:(2)
Finally main_scope in main:(1)
Based on the above behavior, I presume the following.
There is no stack frame creation for the scope {}.
By this way the auto variables, declared/defined in main and those within the sub scope {} share the same stack frame.
So the variables declared/defined in main are free to be accessed anywhere within the function (even within the sub scope).
On the other hand the variables declared/defined in the sub scope loses its scope out of the block.But its life time is valid as long as stack frame is present.
Question: If the above points are right, then why isn't the code failing when giving multiple definitions of the same variable, one within main and the other within {}.

The hardware stack is irrelevant here. It can grow only once for all local variables at function entry and shrink only once at function exit or it can grow and shrink every time a new local variable is defined and destroyed when the enclosing {} for it is left.
What's relevant is the "visibility" of variables.
int main_scope=0;
{
main_scope++;
printf("main_scope++:(%d)\n",main_scope);
// the main_scope variable that was assigned 0 is the most recent
// visible declaration of main_scope.
int main_scope=2;
// now, the previous declaration of main_scope is obscured by the new one,
// and so, you're going to access the new one
printf("Value of redefined main_scope:(%d)\n",main_scope);
}
printf("Finally main_scope in %s:(%d)\n",__FUNCTION__,main_scope);
// the previous scope inside {} is left, so, main_scope is going to be
// the one, to which we assigned 0
It is perfectly legal to define an object in an inner/sub-scope with the same name as in an outer/super-scope. The latter will be obscured for the duration of the {} scope.
Just for the reference, there are some other places, where variable definitions can occur, e.g. inside the first expression of the for(;;) statement: for (int i = 0; i < 10; i++) .... That variable i will only be visible inside the for's body, and you can hide it there as well by defining another i.

Local variable hides the outer variable main_scope.
int main()
{
int i=1;
{
int i=2;
printf("%d", i);
/* Whenever you use i here, it's always the local one that's used.
The outer i is hidden by the local i. But the local i will be deallocated
once the scope exits.*/
}
}
is perfectly legal in C. (Note that this is illegal in C++!)
In your example, certainly a stack frame is created for inner main_scope, but it'll be deallocated once program goes out that inner scope.

Related

Is there efficiency lost when declaring an automatic variable in a frequently opening block scope { }?

In K&R it is stated:
An automatic variable declared and initialized in a block is
initialized each time the block is entered.
Here is a code snippet solely for communicating the question. Two options are shown; declaring error_string in the main function body and declaring it within the block scope of an if().
The question is, if the option2 declaration is used, can the compiler be relied upon to optimize the act of repeatedly instantiating the string?
It may make the code more readable to declare variables closest to where they are used. Limiting their scope as much as possible is perhaps a good design practice. Could doing so have any appreciable detriment to efficiency?
#define MAX_ERROR_STRING_LEN 1024
void process_results(int *results, int n_results)
{
int i;
char error_string[MAX_ERROR_STRING_LEN]; //option1
for (i = 0; i < n_results; i++) //suppose n_results == 1 million, 98% "FAILURE"
{
if (results[i] == FAILURE)
{
char error_string[MAX_ERROR_STRING_LEN];//option2
get_error_string(error_string, MAX_ERROR_STRING_LEN - 1);
fprintf(debug_log, "Error: %s\n", error_string);
}
}
}
on a related note, should this be avoided:
for (i = 0; i < strlen(error_string); i++)
printf("%c", error_string[i]);
in favor of:
int len = strlen(error_string);
for (i = 0; i < len; i++)
printf("%c", error_string[i]);
or will that be optimized despite dependence on run-time data?
Edit - no changes just adding research:
I think this confirms the block scoped variables are repeatedly created and destroyed (for all intents and purposes to the programmer):
A.4.1 Storage Class There are two storage classes: automatic and
static. Several keywords, together with the context of an object's
declaration, specify its storage class. Automatic objects are local to
a block (Par.9.3), and are discarded on exit from the block.
Most of the rest seems to refer to lexical scope rather than linkage:
A.11.1 Lexical Scope ... The scope of a parameter of a function
definition begins at the start of the block defining the function, and
persists through the function; the scope of a parameter in a function
declaration ends at the end of the declarator. The scope of an
identifier declared at the head of a block begins at the end of its
declarator, and persists to the end of the block.
Regarding Lexical scope?:
The scope of a name is the part of the program within which the name
can be used. For an automatic variable declared at the beginning of a
function, the scope is the function in which the name is declared.
Local variables of the same name in different functions are unrelated.
The same is true of the parameters of the function, which are in
effect local variables.
also
A name also has a scope, which is the region of the program in which
it is known, and a linkage, which determines whether the same name in
another scope refers to the same object or function. Scope and linkage
are discussed in Par.A.11.
The local variable error_string is not initialized, there is no overhead in declaring it with block scope instead of function scope. Some compilers might allocate temporary stack space for error_string upon entering the block scope and deallocate it upon leaving this scope, which involves a single instruction in both cases, but most compilers will allocate space for all local variables in a single step at the beginning of the function.
Since you are concerned with efficiency, note that both code fragments posted to print a string are very inefficient compared to this:
fputs(error_string, stdout);

Selecting Static over Global. Why?

The output of the following code is 0.
int account=2;
int main()
{
static int account;
printf("%d",account);
return 0;
}
Why it picked static variable over global variable? Because what I understand is that both global and static variables are stored in the heap and not in function stack , right? So what method it uses to use select one over another?
If multiple variables exist with the same name at multiple scopes, the one in the innermost scope is the one that is accessible. Variables at higher scope are hidden.
In this case you have account defined in main. This hides the variable named account declared at file scope. The fact that the inner variable inside main is declared static doesn't change that.
While the static declaration on a local variable means that it is typically stored in the same place as a global variable, that has no bearing on which is visible when the names are the same.
Consider this small self explaining program:
#include <stdio.h>
int bar = 123; // global variable, can be accessed from other source files
static int blark; // global variable, but can be accessed only in the same
// source file
void foo()
{
static int bar; // static variable : will retain it's value from
// one call of foo to the next
// most compilers will warn here:
// warning declaration of 'bar' hides global declaration
printf("foo() : bar = %d\n", bar); // won't use the global bar but the
// local static bar
bar++;
}
void quork()
{
int bar = 777; // local variable exists only during the execution of quork
// most compilers will warn here as well:
// warning declaration of 'bar' hides global declaration
printf("quork() : bar = %d\n", bar); // won't use the global bar but the
// local bar
bar++;
}
int main() {
foo();
foo();
printf("main() 1 : bar = %d\n", bar);
bar++;
quork();
quork();
foo();
printf("main() 2 : bar = %d\n", bar);
printf("blark = %d\n", blark);
}
Output:
foo() : bar = 0
foo() : bar = 1
main() 1 : bar = 123
quork() : bar = 777
quork() : bar = 777
foo() : bar = 2
main() 2 : bar = 124
blark = 0
Just to clarify for future readers, global and static variables are not stored in heap or stack memory.
https://www.geeksforgeeks.org/memory-layout-of-c-program/
They will either be stored in initialized data or uninitialized data.
Thats not the main question here, which was answered by dbush, but it is a misunderstanding in the original question.
Short answer: encapsulation.
static describes both lifetime and visibility of a variable, and its meaning changes depending on the context. My opinion is that it is one of the more useful and important language features for encapsulation in c. Ignoring the complex relationship to extern, here's a simplified description:
static variables defined at the file level have program lifetime and compilation unit visibility. This means all functions in a .c file can access/modify the variable, but other .c files won't know about the variable. This is super useful for making sure variables used across functions with a compilation unit don't accidentally link with variables in other compilation units. Personally, I highly recommend all file variables to be static by default. Only remove the static specifier if you really want another compilation unit to have access to it (although a getter function may be safer)
Variables declared static within a block scope (most importantly function scope) have program lifetime, and scope visibility. That means it functions as if you declared the variable globally in the file, but only code within that block scope can see it. It also means from one call to the next, the variable does not get destroyed and state can be transferred from call to call.
One really important difference with static variables is that they are default-initialized to zero. This differs from all other variables in c, and is the reason your program prints the value 0. Often times with trivial programs we don't notice the difference because the stack hasn't been polluted with variables yet, but it becomes critical for any program of size.
The most common use for this that I have seen is to enable one-time initialization within a scope. They are also extremely useful for synchronization primitives like pthread_mutex_t. One time I even implemented a state-machine with function-scope static variable.
an example:
int started;//oops, anybody in the entire program can change this value, especially with such a common name!
static int lastCall;
int callCount(void)
{
// This is default-initialized to 0
static int functionStaticVariable;
//Increment each time I'm called
++functionStaticVariable;
//tell the outside world that I'm the one who was called last
lastCall = 1;
//return (a copy of) my internal state.
return functionStaticVariable;
}
char *getSharedMemory(unsigned int bytes)
{
// Here I cannot see functionStaticVariable, but I can see globalVariable
//functionStaticVariable++; // this would cause a compilation failure
// static pointer is default-initialized to zero (i.e. NULL)
static char *sharedMemory;
if(sharedMemory == 0)
{
// This block only executes once, the first time the function is called.
// Actually this is a nice side-effect because it means if the function is never called we don't clutter the stack with unused memory
// Although we will probably never free this memory
sharedMemory = (char *)malloc(bytes);
}
// tell the outside world that this function has been called
lastCall = 2;//valid
//Woah, this is such a bad idea, but actually does _not_ return memory that gets invalidated
return sharedMemory;
}
Hopefully you can see with this pattern you could protect a variable by placing it inside a function and doing optional things like acquiring a mutex-lock in order to allocate the memory. You could even implement the double-lock pattern this way.
I secretly wish that all C++ programmers learned good c encapsulation, because actually the language really encourages it. You can do an incredible amount by placing only functions that need to communicate with each other together in a compilation unit. In a non-OOP language, this can be very powerful.
Full details of static and extern are described by https://en.cppreference.com/w/c/language/storage_duration.
The pragmatic reasoning behind why innermost variable decaration should be the one used: you're not always in control of what's outside your code. You want to be able to write a function that certainly works. If other programmers (say, in a larger team) could break your code just by the way they name variables in other parts of the code, programming would be more of a pain than it is now.

Why's initializing a global variable with return value of a function failing at declaration,but works fine at file scope?

An 80k reputation contributor R.. told me on SO that we can't initialize global variables with the return value of a function as that's not considered a constant,and global variables must be initialized with a constant.And true to his words,I get the following error for this program as expected-- initializer element is not a constant.Here is the program:
#include<stdio.h>
int foo();
int gvar=foo(); //ERROR
int main()
{
printf("%d",gvar);
}
int foo()
{
return 8;
}
But in this context,I just don't understand why the followed altered version of the above program shows no error at all and works fine.In this second program,I am initializing the same global variable with the return value of the same function foo().Can you tell me what is the rigorous technical reason for this variation in results?Why is initializing the global variable with the return value of a function at it's declaration causing error but the same initialization with the same return value works fine when done from within a function?
#include<stdio.h>
int foo();
int gvar;
int main()
{
gvar=foo();
printf("%d",gvar);
}
int foo()
{
return 8;
}
Output 8
The reason behind it is that in order to determine a value produced by a function one needs to execute code, and that there is no code execution done in C when initializing static and global variables.
Compiler and linker work together to prepare a byte image of the global memory segment: the compiler provides the values, and the linker performs their final layout. At runtime, the image of the segment is loaded in memory as is, without further modifications. This happens before any code gets executed, so no function calls can be made.
Note that this does not mean that it is not possible for some technical reason, only that C designers decided against doing it. For example, C++ compiler generates a code segment that calls constructors of global objects, which gets executed before the control is passed to main().
The second version doesn't have an initializer for gvar. gvar is declared and defined at global scope without an initializer. It has static storage duration, so it is initialized with zero.
The assignment in main is just that: an assignment, not an initialization.
In case 1, global variable is assigned with a variable while it is declared.
But in the second case, global variable is assigned(which is already declared) with return value of foo().
Forming of data section, text section all happens during compilation.
Global variables will be in data section(bss or initialized data section), so at compile time, foo() is not invoked right? and return value of foo() is not known during compilation.
But second case, when the text section get executed, gvar is assigned with return value of foo(). It is valid.
You can maybe think of it like this: when main() starts, all global variables must already have their initializer values. And they can't, as you've been told, get those by calling functions since main() is really where execution starts, in a C program.
we could not call any function from outer of the function.Not like shell script.function only allow to called from inside of function body.
In c first execution begins from main(), compiler don't know the function calling if that stands on outer of function it may taken as prototype if arg and return types provided.
we can putting return value of function by calling from main or others function block, to the variable,the function called then (that global) variable modified.
but we can use macro in global variable as needs.
as:
#define max() 12
int glob=max();
main()
{
}

Terminology definition - Scope in C application

Is there a specific term for the following type of C code? In my example, I want to increase the depth of scope for a small chunk of code within a function without having to use needless if/else/for statements so that I can re-declare a variable with the same name multiple times. eg:
void myfunc(void) {
int a = 0, b = 1;
{
int c;
c = 3;
printf("c is: %d", c);
}
a = 2;
{
int c = 5;
printf("c is %d", c);
}
}
What is the term used to describe how I just wrapped some code in curly braces and increased the scope depth so the rest of the function doesn't see the 'c' int?
Thanks!
Scope is defined as the area in which the object is active. There are five scopes in C. They are as follows.
Program Scope
These are the declarations at the top most layers. They are available up to the life of a program. All the functions have this scope. This is otherwise known as global scope.
File Scope
It has scope such that it may be accessed from that point to the end of the file.
void dummy(void) { }
// absence of static automatically gives program scope to `dummy()`
static void dummy(void) { }
// static keyword here gives function `dummy()` a file scope
Function Scope
Only labels have this scope. In this scope, they are active up to end of the function.
void printFun()
{
print:
printf(“i is less than j”);
}
int main()
{
int i=1,j=2;
if(i < j)
goto print;
}
This code will be flagged error by the compiler saying that the label print is not known because labels have only function scope. If you have to jump unconditionally between the functions, you have to use setjmp/longjmp functions.
Block Scope
Declarations that are active up to the end of the block (where a block is defined as statements within { }). All the declarations inside the function have only block scope.
int fun(int a, int b)
{
int c;
{
int d;
}
// a, b, c, d all have block scope
}
As I have said, function scope applies only to labels. So should not be confused with block scope. The function arguments are treated as if they were declared at the beginning of the block with other variables (remember that the function body is also considered as a block within { }). So the function arguments have block scope (not function scope).
Local scope is general usage to refer the scope that is either function or block scope.
Prototype Scope
They are having the scope only inside the prototype declaration. This scope is interesting because the variable names are valid only in the declaration of prototype and does not conflict with other variable names. It exists for very little time and of less use and so goes unnoticed.
int add(int a, float b);
Here the variables a and b are said to have prototype scope.
Selecting Minimal Scope
When a name has to be resolved, that name is searched in the minimal scope, and if that is not available, it is searched at higher levels of scope. So, if a variable has to be declared, you have to select a minimal scope possible. If you can limit your scope, that increases the efficiency, readability and maintainability of your program. If you want a variable which is not useful outside a block, declare it inside the block and not in the outer ones. Similarly, if you want a variable whose value will be accessed only within the function but has to retain the value between the function calls, opt for static variable to a global one.
I'd say you are introducing a new local scope, or a nested scope, or a block.
This becomes seriously important in C++ when you take active advantage of this:
{
std::lock_guard<std::mutex> lk(my_mutex);
do_critical_stuff(); // might throw exception?
}
// the lock is released automagically!
But even in C it's good practice to only use variables locally where they're needed and not bleed them into unnecessarily wide scopes.
The term is the scope.
K&R2 defines the word scope as
A name also has a scope, which is the region of the program in which
it is known
Scope is the word that refers to the visibility of an identifier.

c variables scope

if a variable is defined in a block is it present in the block only or throughout the program?
for example
main()
{
int j=5;
{
int i=10
printf("%d",i);
}
printf("%d , %d ",i,j);
}
is it valid
main()
{
int j=5, *k;
{
int i=10
printf("%d",i);
}
k=&i
printf("%d , %d ",*k,j);
}
as variable remains in memory from the point of its declaration to the point wen function exits?
A non-global variable's scope is limited to the block it's defined in. Furthermore, for an automatic variable, once the block ends the variable's lifetime is over.
Consider this silly example:
void doit()
{
int *ps;
int *pa;
{
static int s = 1;
int a = 2;
ps = &s;
pa = &a;
}
// cannot access a or s here because they are out of scope
// *ps is okay because s is static so it's lifetime is not over
// *pa is not okay because a's lifetime ends at the end of the block
}
Your second printf line will not compile because i is not in scope.
It's only accessible within the block, so in your example the second printf() is illegal and will not compile.
Yes its scope is then limited to the block where it is located.
The scope of i is limited within the block where it is declared. In your case it is
{
int i=10
printf("%d",i);
}
Hence i is not accessible outside this scope
This question also relates to your question about local scope or an auto variable.
Scope can be defined as the module within which this variable is defined.
And a module may be a function or a file.
So you can declare an auto variable in a file - which would mean it can be accessed by every function in that file, or put another way - its scope is defined to be the file in this case.
If you declare the same variable as auto, but within a function, it would mean that it can only be accessed within that function - or its scope is defined to be the function in this case.
Think of auto as 'local' within a module (where module may be a function or a file).
In the example above, you have defined the scope by adding the braces, and therefore the scope of variable i is localised to within the braces, which is why you have limited access outside the braces.

Resources