Saturday, January 7, 2012

staic vs const vs static const vs const volatile

explain the difference between static, const & static const varibales  & methods.

const volatile:
const volatile usigned int *REG_A = (usigned int *) init_hardware_n_return_address of REG_A();

In the above snippet function "init_hardware_n_return_address of REG_A()" modifies the content of the REG_A( register A say) of a peripheral device , say after initiatialising it ( which cause the content of R/W register REG_A modified by peripheral itself) and returns the address of REG_A to the program .

The assignment in the above snippet implies here that content of REG_A can be modifiable only be external sources like peripheral hardware itself and and your code is not supposed to modify the content of REG_A . Also whenever such variable is encountered compiler should "load " it value every time instead of doing any code optimasation
Typically memory mapped variables are one consumers for such usage

Concept of Indivisible Operations:

Those of you who are familiar with techniques that involve hardware interrupts and other ‘real time’ aspects of programming will recognise the need for volatile types. Related to this area is the need to ensure that accesses to data objects are ‘atomic’, or uninterruptable.
Be careful not to assume that any operations written in C are uninterruptable. For example,

extern const volatile unsigned long realtimeclock;
 
could be a counter which is updated by a clock interrupt routine. It is essential to make it volatile because of the asynchronous updates to it, and it is marked const because it should not be changed by anything other than the interrupt routine. If the program accesses it like this:
unsigned long int time_of_day;

time_of_day = real_time_clock;
there may be a problem. What if, to copy one long into another, it takes several machine instructions to copy the two words making up real_time_clock and time_of_day? It is possible that an interrupt will occur in the middle of the assignment and that in the worst case, when the low-order word of real_time_clock is 0xffff and the high-order word is 0x0000, then the low-order word of time_of_day will receive 0xffff. The interrupt arrives and increments the low-order word of real_time_clock to 0x0 and then the high-order word to 0x1, then returns. The rest of the assignment then completes, with time_of_day ending up containing 0x0001ffff and real_time_clock containing the correct value, 0x00010000.
This whole class of problem is what is known as a critical region, and is well understood by those who regularly work in asynchronous environments. It should be understood that Standard C takes no special precautions to avoid these problems, and that the usual techniques should be employed.
The header ‘signal.h’ declares a type called sig_atomic_t which is guaranteed to be modifiable safely in the presence of asynchronous events. This means only that it can be modified by assigning a value to it; incrementing or decrementing it, or anything else which produces a new value depending on its previous value, is not safe.

Compiler interpretation of const volatile:

Let us see an example to understand how compilers interpret volatile keyword. Consider below code, we are changing value of const object using pointer and we are compiling code without optimization option. Hence compiler won’t do any optimization and will change value of const object.
/* Compile code without optimization option */
#include <stdio.h>
int main(void)
{
    const int local = 10;
    int *ptr = (int*) &local;
    printf("Initial value of local : %d \n", local);
    *ptr = 100;
    printf("Modified value of local: %d \n", local);
    return 0;
}
When we compile code with “–save-temps” option of gcc it generates 3 output files
1) preprocessed code (having .i extention)
2) assembly code (having .s extention) and
3) object code (having .o option).
We compile code without optimization, that’s why the size of assembly code will be larger (which is highlighted in red color below).
Output:
[narendra@ubuntu]$ gcc volatile.c -o volatile –save-temps
  [narendra@ubuntu]$ ./volatile
  Initial value of local : 10
  Modified value of local: 100
  [narendra@ubuntu]$ ls -l volatile.s
  -rw-r–r– 1 narendra narendra 731 2016-11-19 16:19 volatile.s
  [narendra@ubuntu]$
---------------------------------------- 

Let us compile same code with optimization option (i.e. -O option).  In thr below code, “local” is declared as const (and non-volatile), GCC  compiler does optimization and ignores the instructions which try to  change value of const object. Hence value of const object remains same.
/* Compile code with optimization option */
#include <stdio.h>
int main(void)
{
    const int local = 10;
    int *ptr = (int*) &local;
    printf("Initial value of local : %d \n", local);
    *ptr = 100;
    printf("Modified value of local: %d \n", local);
    return 0;
}
For above code, compiler does optimization, that’s why the size of assembly code will reduce.
Output:
[narendra@ubuntu]$ gcc -O3 volatile.c -o volatile –save-temps
  [narendra@ubuntu]$ ./volatile
  Initial value of local : 10
  Modified value of local: 10
  [narendra@ubuntu]$ ls -l volatile.s
  -rw-r–r– 1 narendra narendra 626 2016-11-19 16:21 volatile.s
----------------------------------------- 

Let us declare const object as volatile and compile code with  optimization option. Although we compile code with optimization option,  value of const object will change, because variable is declared as  volatile that means don’t do any optimization.

/* Compile code with optimization option */
#include <stdio.h>
int main(void)
{
    const volatile int local = 10;
    int *ptr = (int*) &local;
    printf("Initial value of local : %d \n", local);
    *ptr = 100;
    printf("Modified value of local: %d \n", local);
    return 0;
}
Output:
[narendra@ubuntu]$ gcc -O3 volatile.c -o volatile –save-temp
  [narendra@ubuntu]$ ./volatile
  Initial value of local : 10
  Modified value of local: 100
  [narendra@ubuntu]$ ls -l volatile.s
  -rw-r–r– 1 narendra narendra 711 2016-11-19 16:22 volatile.s
  [narendra@ubuntu]$
The above example explains how compilers interpret volatile keyword. As a practical example, think of touch sensor on mobile phones. The driver abstracting touch sensor will read the location of touch and send it to higher level applications. The driver itself should not modify (const-ness) the read location, and make sure it reads the touch input every time fresh (volatile-ness). Such driver must read the touch sensor input in const volatile manner.

Useful Links:
http://embeddedgurus.com/barr-code/2012/01/combining-cs-volatile-and-const-keywords/
http://msdn.microsoft.com/en-us/library/145yc477%28v=vs.80%29.aspx

No comments:

Post a Comment