Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

What’s up with Storage classes in C

runtime variable type

  • Please log in to reply
No replies to this topic

#1 fkl

fkl

    CC Devotee

  • Senior Member
  • PipPipPipPipPipPip
  • 417 posts

Posted 03 July 2011 - 01:34 PM

What’s up with Storage classes in C?

It is a frequently asked question in programming interviews. Sometimes people know partial answers, at others they just mix them up. So I thought of explaining from the basics till some deep aspects of how they reside in memory and its impact on program behavior.

Also there have been a good number of related posts on this topic which can be complimented such as
http://forum.codecal...eader-file.html
http://forum.codecal...tic-status.html
http://forum.codecal...gro-c-game.html
Most of this applies to C++ too however, I wouldn’t go into usages specific to c++. For e.g. I won’t discuss the use of static keyword in c++ or more precisely in classes since for now my scope is C only and secondly, this c part seems to be the lesser known one.

So storage classes are basically keywords that we add before a variable type (such as in static int B) which tells the compiler about the life time of a variable i.e. where will the variable be stored and how long with it live.

Primarily there are four of these i.e. automatic, static, extern and register. Sometimes another one is added known as volatile. Let’s discuss them one by one.

Automatic a.k.a. Locals
Automatic (more commonly ‘local’) variables are the most trivial ones. They are actually created as in

auto int a;
int a ;  // both of above have the same meaning

This tells the compiler to create a variable with local or automatic scope. However, something strange happened. When I compiled this on VC++ 2010, it gave me compiler error saying auto cannot be combined with another type specifier and strange enough

auto a = 4; // was not an error and deduced it to be an int where as
auto a; // was a compiler error

I googled a little and found Microsoft has slightly changed the usage of auto starting VS 2010
auto Keyword (Type Deduction)

But any way older compiler would work that way and because by default variables are “local” so the keyword is seldom used. Hence the above change by MS is fine.

The important point to know is, automatic variables are stored on program stack. This would mean they only exist within a function’s scope. If we create a variable in main it will be visible through out main but not outside. If I write a function foo containing variable v, it will only be visible inside foo and not beyond.

Statics
These are very renowned ones and favorites for programming interviews. But are seldom fully known.
First, static variables have the life time of entire program i.e. they are not going to be destroyed as long as the program lives. However, this does not change their ACCESS scope for instance

somefunction()
{
	static in s = 4; // critical line
	cout << s << endl;
	s++;
}

int main()
{
	somefunction();
	somefunction();
return 0;
}

Try the above code. Some would say it would print 4 twice on the screen. However, it will actually print a 4 and 5 on the screen. The reason being the critical line with providing an initial value to the static variable is executed only ONCE. So in all successive calls, the previous value of s is retained though it was created as a local variable.

But in the above case, s is NOT accessible outside of somefunction(). It is common to be mistaken about scope which means to what extent a variable is visible and therefore usable in code. The scope of s is limited to somefunction() only. However, it will live and retain it’s value as long as the program lives.

Second important point about static variables is related to global variables. What if you create a variable like

int g = 5;

outside of any function. This is a global variable and accessible as well as lives throughout the program.

What is the relation with static? It already contains the property of living through the entire program for static. What if I add a keyword static to this global variable? i.e.

static in g = 5; // this is outside of any function

Will there be any additional impact of making this variable static? Yes, but that is the second usage of static. It tells the compiler to restrict access to this variable to only with the current file (translation unit). So there would be no way to read this variable from code which resides in another file. If this static keyword is added to a function i.e.

static int fun(int b);

Then this function will not be accessible outside of the current file.

One other important aspect regarding static variables is that if we do not initialize them, they are by default initialized to zero. However, this is not that simple. Another related question is Where are the static variables stored? In stack? Healp? Some where else?

All of the above questions are answered collectively.

There are two types of static variables:

1. Initialized static variables. The ones we write like

static int a = 4;

fall into this category and are stored in Data Segment of the program.
It is a section which contains global variables as well as the initialized static ones. So these are the ones which the programmer initializes himself to some value.

2. Uninitialized static variables. The one written as

static in b;

are initialized to zero on runtime (since I mentioned statics are always initialized whether we explicitly do so or not). But these are stored in another section of memory called BSS which stands for “block started by symbol”. Technically everything contained in this section is initialized to 0 at run time.

Sometimes BSS along with heap is referred as a part of Data segment however the distinction remains there.

This also implies a very important meaning. If you create initialized static variables, they will be allocated memory on compile time and their values will be stored in DS which will be taking space in an object file and ultimately in final exe. Whereas if you create an uninitialized static variable, it will still be initialized at run time being part of BSS and it’s value will not be present in exe and will only be loaded at run time.

Try creating a simple program containing a large static array. Let it remain uninitialized, create exe and note down it’s size. Then initialize it, generate exe and note down the size. You will see a significant difference.

Register
Register keyword is a simple request to compiler to place the variable in question in a cpu register for faster access. The compiler may or may NOT grant such a request. Generally it will be used in a situation when you have frequent access to a variable and you want to optimize access to it. In practice, this is not used very frequently because compilers have already optimized frequently used variables.

register int b;

Extern
A few paragraphs above I mentioned static when applied to a global variable restricts it’s access to a file. But how do you allow access to a variable from another file?
By default for a given variable name, compiler only searches it with in the current file (translation unit) and flags an error if not found. So to get through this we have a special keyword called extern.

Suppose you have two files where file 1 contains variable a, which is required to be accessed in file 2.
Important thing is, extern keyword is added in the file in which the variable is to be used i.e. in file 2.

File1.c
int a = 5;

File2.c
extern int a; // tells the compiler to look for this variable in other files at link time

The above can also apply to arrays, functions etc. as well. However, there is a catch as I have mentioned before in a thread too
http://forum.codecal...html#post305387

If you extern something, it’s type checking is over at compile time, so even if you declare extern in a and it finds a double a at runtime, there is no way compiler can flag an error as there is no type checking at link time. Same applies to size of an array.

This is the reason, it is a good practice to create proper header files and include them in your source files. That way, compiler catches all type differences and flags error if any.

Volatile
It is again a request to compiler (which may or may not be honored) NOT to optimize a variable i.e.

volatile int v;

This actually means that compiler should not copy this variable into some register and keep on reading value from that register for faster access. Why would that be needed? For e.g. we have two threads modifying the same shared variable which is used in a huge loop counter on one side. Now loop counter would be one of the favorites for a compiler to optimize. But we have unexpected situations in which the other thread might change the value of this variable.

In that case we want to compiler to always access and read the value of original variable from the memory. So this keyword may be useful in that scenario.

However, remember there is no guarantee that by using volatile a variable wouldn’t be optimized or using register a variable would be optimized. Compiler may or may not honor depending upon it’s own constraints specific to that program.
  • 1
Today is the first day of the rest of my life





Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download