DEV Community

Khaled Mustafa
Khaled Mustafa

Posted on

Scope and lifetime of variables

Table of Contents

  1. Memory layout of a program in C
    1. RAM
    2. ROM
    3. What is the difference between a statically defined variable and a dynamically defined variable?
  2. Scope of a variable
    1. Block scope
    2. File scope
    3. Program scope
  3. What is the difference between a variable definition and declaration?
  4. Storage classes
    1. auto
    2. static
    3. extern
    4. register

Memory layout of a program in C

Before jumping into exploring the scope and lifetime of a variable in C we first need to define the memory layout of a common program.
As we know we, have two types of memories RAM (Random Access Memory) which is used for storing the data generated by a program, and ROM (Read Only Memory) which is used for storing the instructions of a program.

RAM

+---------------------+
|    Memory Mapped    |
|    Peripherals      |
+---------------------+
|    Initialized      |
|    Data Segment     |
+---------------------+
|    Uninitialized    |
|    Data Segment     |
+-----+---------------+
|     | Heap          |
|     |               |
|     v               |
|                     |
|                     |
|                     |
|                     |
|     ^               |
|     |               |
|     | Stack         |
+-----+---------------+
Enter fullscreen mode Exit fullscreen mode
  • RAM is divided into mainly four portions:
    1. Memory Mapped Peripherals
    2. Initialized Data Segment: This segment contains all variables that have been initialized with a value.
    3. Uninitialized Data Segment (bss) Contains all uninitialized variables (those that have been defined but not assigned any value)
    4. Heap
    5. Stack

ROM

+---------------------+
| Interrupt Vector    |
| Table (IVT)         |
+---------------------+
| Text Segment        |
|                     |
+---------------------+
| Constant data       |
| Segment (.ro data)  |
+---------------------+
| Boot loader         |
|                     |
|                     |
+---------------------+
Enter fullscreen mode Exit fullscreen mode

What we are concerned with here is the text segment which is used for storing the instruction (code) of the program, and the constant data segment which is used for the storage of every statically defined constant.

What is the difference between a statically defined variable and a dynamically defined variable?

Variables that have a value before the run-time of the program are called statically defined variables while variables that don't have a value before the runtime of the program and are assigned a value during the runtime and will get its value from elsewhere are known as dynamically defined variables.

Scope of a variable

The scope of a variable is the region in which we can use a variable.
There are three different variable scopes in C:

  1. Block scope (Function scope)
  2. File scope
  3. Program scope

Block scope

  • Variables having this type of scope are limited in their usage to the region (block) in which they were defined, we can not use it outside the code block.
  • A block (code block) is the whole region starting with { and ending with }.

File scope

  • Variables that we could refer to in any location in the file in which they have been declared.
  • There are two storage classes that we are concerned with regarding the file scope, static and extern.
  • static storage class has two completely different consequences on a variable (depending on the type of the variable it's used on), if the variable is local then it increases its lifetime to the whole program, and if the variable is global it limits its scope to the module (file) it was defined in, in other words, we can't use the keyword extern on such variables.

Program scope

  • These are all non-static global variables, such that they could be accessed from anywhere in the program, but to use a global variable that has been defined in a file (module) elsewhere from where we intend to use we must first declare it.
  • The lifetime of a global variable is the whole lifetime of the program.

What is the difference between a variable definition and declaration?

  • Declaration is informing the compiler of the existence of a variable, so that compiler could ignore it for the time being and later the linker comes and links a value to that variable, we can never use a variable that has not been first declared.
  • Declaration involves specifying the variable with a symbol and a data type. Example for this the keyword extern int k is just informing the compiler that there is a variable called k and it's of data type int that has been defined somewhere else in the program, use it for now and the linker will handle its value.
  • Only functions and constants could be only declared, rather than defined and declared.
  • A definition provides the compiler with all the information it needs to generate machine code when the entity is used later in the program, (the linker doesn't have a job when the compiler can see the definition of a variable).
  • Since constant variables are static variables (i.e. They must have a value before the run-time of the program) a definition must be provided by the programmer before the compilation process.
  • A declaration of a built-in type such as int is automatically a definition because the compiler knows how much space to allocate for it.
  • Examples:
/* Delcare and define int variables i and j. */
int i = 0;
int j;

/* Decleration without definition. */
extern int k;

int main()
{
  /* This results in an error because there is no declaration instance for the variable l.
      error: ld returned 1 exit status */
  i = k + l;
}
Enter fullscreen mode Exit fullscreen mode

Storage classes

  • C provides different types of storage classes, the most commonly used ones are:
  1. auto
  2. static
  3. extern
  4. register

Let's take everything and know what it does.

auto

  • This specifier class is rarely used as it's the default storage class for block-scoped variables.
  • Each time a block is entered storage for auto variables defined in that block is made available and ceases to exist as soon as we exit the block.
  • The allocation and de-allocation of the variable in memory are done automatically, hence the name.
  • All uninitialized auto variables have garbage values so we must initialize them before we use them.
  • Example:
/* Both these variables are similar to each other. */
int x;
auto int x;
Enter fullscreen mode Exit fullscreen mode

static

  • It has two different effects on a variable depending on its scope whether is local or global.
  • If the variable is local, the static specifier extends its lifetime to be the whole program, but it doesn't extend its scope, its scope is limited to the function it was defined in.
  • static in block scope (local variable) with an initializer will only be initialized one time on program startup, not each time the function is called.
  • Since its lifetime has been extended its storage location has changed from a normal local variable stored on the stack to a constant variable stored in the program memory.
  • Example:
void myFunc(int i)
{
  int x = 2;
  static int result = 0;
  result += x;
  printf("The result is %d on the %d iteration.\n", result, i);
}

int main(void)
{
  for (int i = 0; i < 4; i++)
  {
    myFunc(i);
  }
}
Enter fullscreen mode Exit fullscreen mode
  • In essence, the static specifier transfers the value of the variable from one function call to another.
  • When used on a global variable the static specifier limits the scope of this variable to only the file (module) it has been defined in (i.e. In other words we can't use the keyword extern on such variables).
  • The static specifier could also be used on function limiting its usage the same way it does to global variables.

extern

  • It's used for informing the compiler (declaring) that a variable of a specific name and data type exists somewhere in the program and for now just use it as it's and the linker will handle the assignation of a value to it.
  • In essence, it's used to extend the scope of a global variable.
  • Example, if we have two files file1.c and file2.c:

  • file1.c

/*Decleration and defintion of a global variable x.*/
int x = 8;
Enter fullscreen mode Exit fullscreen mode
  • file2.c
#include "file1.c"

int main(void)
{
  extern int x;

  printf("The value of x %d.\n", x);

  return 0;
}
Enter fullscreen mode Exit fullscreen mode
  • Notice that including a C file into another file is a legal, but not advisable thing to do, what we rather would do in a real program is define our variables in a header file and then include it, this example is for illustration only.

register

  • This specifier is used for storing the variable in a register, this is done to decrease the time the program is required to access the memory we know that this variable will be accessed multiple times throughout the lifetime of the program.
  • The compiler doesn't guarantee that it will store the specified variable in the register, if no freely available register this specifier would be ignored.

Top comments (0)