Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/articles/c-tutorials/)
-   -   Complete Guide to Understanding static in C (http://www.go4expert.com/articles/complete-guide-understanding-static-c-t29319/)

Trinity 2Dec2012 17:52

Complete Guide to Understanding static in C
 
The keyword ‘static’ has been widely used in many programming languages. I know it is there in Java, C and C++. I am pretty sure, it is must be used in other languages as well, even though it might depict different attributes and characteristics. However, we are going to learn about the keyword ‘static’ in C, what does that mean, and where and why to use it.

The Keyword ‘static’ in C



In C, a variable or a function can be defined ‘static’. One can define a variable or a function static by just prefixing it with the keyword ‘static’. Here is a sample:

Code:


/*Static Variable*/
static int sVar;

/*Static Function Prototype*/
static int myFunc();

/*static Function Definition*/
static int myFunc()
{
…..

}

Therefore, to make a variable static, just prefix its declaration with the keyword ‘static’. And to make a function static, prefix its prototype and definition with the keyword ‘static’.

Making a variable static in C means to create just one instance of it of it and that too at the beginning of the program execution. Making a function static in C, means that the function can only be used within that file.

Static Variables



As stated, for C static variables, memory is allocated once the program begins, and de-allocated when the program exits. Therefore they have a lifetime for the entire run of the program. However, it has a limited scope. In case of global static variables, i.e. if declared at the top of a C file, its scope is limited to the file only. Hence, it would not be visible outside the file. In case of local static variable of a function, its scope is limited to that function and not visible to code outside the parenthesis of the function. Lets understand the scope and lifetime of a static variable with the help of some examples.

Understanding the lifetime of the static variable

In the following code, we want a function such that it returns the next character of a string every time it gets called. However, it can be easily done by passing the index of the string as a parameter, and the function doesn’t care about maintaining the index. What if, we don’t want to pass a parameter to the function as it adds up to the stack every time the function is called.
The solution is a static variable, whose extended life time helps in maintaining the index of the string. Here is an example code:
Code:

#include <stdio.h>
#define MAX 20
#define STRING "Go4Expert"

char getNextChar();

int main()
{
    char ch;
    int i = 0;
    char myStr[MAX];

    /*Run a loop for each character of the STRING*/
    while ((ch = getNextChar()))
    {
        myStr[i++] = ch;
        myStr[i++] = '.';
    }

    /*Null terminating the string*/
    myStr[i] = 0;
    printf(" The output string is %s\n", myStr);

    return 0;
}

char getNextChar()
{
    static int index = 0;
    char retCh;

    retCh = STRING[index];
    index++;

    return retCh;
}

In the code, having a closer look at the definition of the function “getNextChar()”,

Code:

char getNextChar()
{
    static int index = 0;
    char retCh;

    retCh = STRING[index];
    index++;

    return retCh;
}

It declares a static integer variable ‘index’, which is incremented once for each call to this function. Since, the variable ‘index’ is allocated memory in the process image when the executable begins running, it gets maintained there. Any modification to its value is retained even when the function returns. Therefore, once incremented from
Code:

index = 0
to
Code:

index = 1
, the value of ‘index’ is updated to ‘1’. When the next time a call is made to ‘getNextChar()’, the value of ‘index’ is still ‘1’ and get incremented to ‘2’ now. Hence, this is how, it always retrieves us the next index of the string, without us worrying about passing ‘index’ as a parameter or even adding an extra effort code to maintain it. It was simply done using a static variable because of the its lifetime till the complete run of the program.

To see the output:
Code:

The output string is G.o.4.E.x.p.e.r.t.
which is pretty expected after understanding the static variable lifetime.

Understanding the scope of the static variable

Moving on to understanding how scope of the static variable affects, lets create a full fledged application with multiple source files. With an intention to give a simple example, we are coding the most unreal and abstract kind of a metadata engine which will give audio metadata.

File : audio.c
Code:

#include <stdio.h>

unsigned int size = 12;

unsigned int getSizeAudio()
{
    return size;
}

void setSizeAudio(unsigned int val)
{
    size = val;
}

int main()
{
    setSizeAudio(33);
    printf("Size of Audio is %d\n", size);

    return 0;
}

The source stores size of the audio file in a global variable which are managed through functions. The above program sets and receives the size metadata.

Lets compile it and run it.
Code:

rupali@home-OptiPlex-745:~/programs/cstatic$ gcc audio.c -Wall -o audio
rupali@home-OptiPlex-745:~/programs/cstatic$ ./audio
Size of Audio is 33

All works fine and as expected.

However, now we wish to add another feature to get or set metadata of video as well. So, we write another source code to support video as”

File : video.c
Code:

#include <stdio.h>

unsigned int size = 100;
unsigned int duration;

unsigned int getDurationVideo ()
{
    return duration;
}

unsigned int getSizeVideo()
{
    return size;
}
void setDurationVideo (unsigned int val)
{
    duration = val;
}

void setSizeVideo(unsigned int val)
{
    size = val;
}

This again stores the size and duration in global variables and manage them through functions. Lets compile both the sources to form object files.

Code:

rupali@home-OptiPlex-745:~/programs/cstatic$ gcc -c audio.c -Wall -o audio.o
rupali@home-OptiPlex-745:~/programs/cstatic$ gcc -c video.c -Wall -o video.o

Now link, both together to build an executable ‘mdataEngine’
Code:

rupali@home-OptiPlex-745:~/programs/cstatic$ gcc video.o audio.o -o mDataEngine
audio.o:(.data+0x0): multiple definition of `size'
video.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status

Ohhh, we got a linking error of multiple definition of size. If we check back, compiler points out that the variable ‘size’ has been defined twice, once in audio.c and other in video.c. Until, they were compiled in their separate compilation unit, it was fine. When linked together, symbol resolution got confused and that’s why points out that the global variable ‘size’ is being defined in both the source files.

However, it is our requirement to use ‘size’ in both the files as in audio.c it represents the audio size, whereas in video.c, it represents the video size.

The solution is using ‘static’ variable whose scope is limited within the file in which its defined. Hence, ‘size’ in audio.c would not be visible to video.c and vice versa.

Here is how the sources look like using static variables,
File : audio.c
Code:

#include <stdio.h>

static unsigned int size = 12;

unsigned int getSizeAudio()
{
    return size;
}

void setSizeAudio(unsigned int val)
{
    size = val;
}

int main()
{
    setSizeAudio(33);
    printf("Size of Audio is %d\n", size);

    return 0;
}

File : video.c
Code:

#include <stdio.h>

static unsigned int size = 100;
static unsigned int duration;

unsigned int getDurationVideo ()
{
    return duration;
}

unsigned int getSizeVideo()
{
    return size;
}
void setDurationVideo (unsigned int val)
{
    duration = val;
}

void setSizeVideo(unsigned int val)
{
    size = val;
}

Now, let’s compile and link:
Code:

rupali@home-OptiPlex-745:~/programs/cstatic$ gcc -c audio.c -Wall -o audio.o
rupali@home-OptiPlex-745:~/programs/cstatic$ gcc -c video.c -Wall -o video.o
rupali@home-OptiPlex-745:~/programs/cstatic$ gcc video.o audio.o -o mDataEngine

The error is gone!

Now we know in what kind of scenarios static variables are most suited and should be used.

In the ELF



All uninitialized static variables go to the .bss section of the ELF process image. And hence, all uninitialized static variables are by default initialized to zero.
Besides, all explicitly initialised variables are part of the .data section.

This can be easily verified through the objdump linux command. Using the already compiled ‘video.o of the above example,
(objdump with -t’ option displays the symbol table. Learn the basic usage of objdump through its man page.)
Code:


rupali@home-OptiPlex-745:~/programs/cstatic$ objdump -t video.o

video.o:    file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*        00000000 video.c
00000000 l    d  .text        00000000 .text
00000000 l    d  .data        00000000 .data
00000000 l    d  .bss        00000000 .bss
00000000 l    O .data        00000004 size
00000000 l    O .bss        00000004 duration
00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack
00000000 l    d  .comment        00000000 .comment
00000000 g    F .text        0000000a getDurationVideo
0000000a g    F .text        0000000a getSizeVideo
00000014 g    F .text        0000000d setDurationVideo
00000021 g    F .text        0000000d setSizeVideo

Note here the symbol ‘size’ is part of .data section as it has been initialised whereas symbol ‘duration’ is part of .bss section as it is uninitialized.

Static Functions



Static Functions as already mentioned are the ones which have limited scope within the file in which it has been defined. Its exactly the same scope concept as that of the static variable explained in the section above. To illustrate with a help of a simple example, Again, to explain scope of static function, we need to take multiple sources.

The header file with the prototypes.
File : sfunc.h
Code:

void printN ();
static void _printS();

The source file with the definitions of a non static function and a static function.
File : sfunc.c
Code:

#include <stdio.h>
#include "sfunc.h"

void printN ()
{
    printf("In printN\n");
    _printS();
}

static void _printS ()
{
    printf("In static _printS\n");
}

The main source file
File : main.c
Code:

#include <stdio.h>
#include "sfunc.h"

int main()
{
    printf("Main started\n");
    printN();
    _printS();

    return 0;
}

Let’s compile the sources
Code:

rupali@home-OptiPlex-745:~/programs/cstatic/$ gcc main.c sfunc.c -Wall -o main
sfunc.h:3:13: warning: \u2018_printS\u2019 used but never defined
/tmp/cc8Wb2xL.o: In function `main':
main.c:(.text+0x1b): undefined reference to `_printS'
collect2: ld returned 1 exit status

Its again a error saying main.c source file could not find the definition of _printS() function. Note this is a static function defined in ‘sfunc.c’, which should explain the error. _printS() being a static function is only visible within ‘sfunc.c’ When the linker tried to resolve it in file ‘main.c’, it could not find any visible definition and hence complained about it through the linking error.

Now, to confirm, lets remove the call to _printS() from ‘main.c’ and see if that makes the error go.

File : main.c
Code:

#include <stdio.h>
#include "sfunc.h"

int main()
{
    printf("Main started\n");
    printN();

    return 0;
}

Compiling again,
Code:


rupali@home-OptiPlex-745:~/programs/cstatic/$ gcc main.c sfunc.c -Wall -o main
rupali@home-OptiPlex-745:~/programs/cstatic/$ ./main
Main started
In printN
In static _printS

It works fine. Hence, we know that static functions should only be defined when our requirement includes it to be invisible and not accessible to other sources.

Rajesh M. Kanojia 14Dec2012 01:17

Re: Complete Guide to Understanding static in C
 
really helpfull article.
thank's


All times are GMT +5.5. The time now is 09:15.