Explore the meaning of the keyword volatile in C

  • 2020-04-02 00:51:17
  • OfStack

Volatile means "volatile, volatile, volatile." The meaning of this qualifier is to indicate to the compiler that the contents of a variable may change due to changes in other programs. Usually when a variable is declared in a program, the compiler tries to store it in a general-purpose register, such as ebx. When the CPU puts its value in ebx, it no longer CARES about the value in memory. If at this point another program (such as a kernel program or an interrupt) modifies its value in memory, the value in ebx is not updated. To address this situation, the volatile qualifier was created, making it mandatory for code to reference the variable to get its value from the specified location.

What does the keyword volatile mean? And give three different examples. A variable that is defined as volatile means that the variable may be changed unexpectedly so that the compiler does not assume the value of the variable. To be precise, the optimizer must carefully re-read the value of this variable each time it is used, rather than using a backup stored in a register. Here are some examples of volatile variables:
1). Hardware register of parallel device (e.g. status register)
2). Non-automatic variables that are accessed by an interrupt service subroutine
3). Variables Shared by several tasks in multithreaded applications
People who can't answer this question will not be hired. I think this is the fundamental problem that distinguishes C programmers from embedded system programmers. Embedded system programmers often deal with hardware, interrupts, RTOS, and so on, all of which require volatile variables. Not understanding volatile content can be disastrous.
Assuming the interviewee answers this question correctly (well, doubt it), I'll dig a little deeper to see if the guy understands the full importance of volatile.
1). Can a parameter be either const or volatile? Explain why.
2). Can a pointer be volatile? Explain why.
3). What's wrong with the following function?
Int square (volatile int * PTR)
{return * PTR * * PTR. }
Here's the answer:
1.) yes. One example is the read-only status register. It's volatile because it can be changed unexpectedly. It's const because the program shouldn't try to change it.
2). Yes. Although this is not very common. An example is when a service subroutine in a file modifies a pointer to a buffer.
3). This code has a prank. The purpose of this code is to return the * PTR to the square of the value, but since * PTR points to a volatile parameter, the compiler produces something like this:

int square(volatile int *ptr) 
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}

Because the value of * PTR may be unexpectedly changed, a and b may be different. As a result, this code may not be the square you expected! The correct code is as follows:

long square(volatile int *ptr) 
{
int a;
a = *ptr;
return a * a; }


Volatile means volatile    
Because registers are accessed faster than RAM, compilers generally optimize for less access to external RAM. Such as:

static   int   i=0; 
int   main(void) 
{ 
        ... 
        while   (1) 
        { 
                if   (i)   dosomething(); 
        } 
} 
 
void   ISR_2(void) 
{ 
          i=1; 
} 

The program is intended to call the dosomething function in main when the ISR_2 interrupt occurs, but the compiler determines that the I has not been changed in main, so
It is possible to read from I to a register only once, and then use only the "I copy" in the register for each if judgment, so that dosomething is never called. If a variable is to be made volatile, the compiler guarantees that no reads or writes to that variable will be optimized (they will certainly be executed). In this case I should say the same thing.
In general, volatile is used in the following places:
1. The variables modified in the interrupt service program for detection by other programs need to be volatile;
2. In a multi-task environment, the flags Shared between tasks should be volatile;
3. Memory-mapped hardware registers are also usually volatile because each read or write to them may have a different meaning.
In addition, the above cases often have to consider the integrity of the data at the same time (several signs related to each other were broken in the middle of the rewrite), in 1 can be implemented by turning off the interrupt
Now, task scheduling can be disabled in 2, and only good hardware design can be relied on in 3.
/ / = = = = = = = = = = = = =
Pointer types are also variables, so they can also be modified with volatile.
The volatile keyword is a type modifier that declares a type variable that can be changed by some factor unknown to the compiler, for example
Operating system, hardware, or other threads. When a variable declared by this keyword is encountered, the compiler no longer accesses the code for that variable
Optimized to provide stable access to specific addresses.
Examples of using this keyword are:
int     volatile     NVint;
Volatile is used when required     When declaring the value of a variable, the system always rereads the data from the memory where it is located, even if it is preceded by a pointer
Let the data have just been read from there. And the read data is saved immediately.
Such as:
volatile     int     I = 10;
int     a.     =     I;
. // other code that does not explicitly tell the compiler that I was manipulated
int     b     =     I;
volatile     Pointed out that     I can change at any time and must be read from the address of I every time it is used, so the compiler generates it
The assembly code will re-read the data from I's address and place it in b. The optimization is done because the compiler finds code between reads from I
The code does not manipulate I, and it automatically puts the last read data in b. Instead of reading from I again. So if
I is a register variable or represents an error-prone port data, so volatile guarantees stable access to a particular address.
Note that in vc6, there is no code optimization in general debug mode, so the use of this keyword is not apparent. Let's go ahead and insert the assembly
Code, test whether there is volatile keyword, the impact on the final code of the program:
Start by building a win32 using the classwizard     For the console project, insert a voltest.cpp file and enter the following code:

#include   <stdio.h> 
void   main() 
{ 
  int   i=10; 
  int   a   =   i; 
  printf( "i=   %dn ",a); 
                //The following assembly statement changes the value of I in memory without letting the compiler know
  __asm   { 
    mov                   dword   ptr   [ebp-4],   20h 
  } 
  int   b   =   i; 
  printf( "i=   %dn ",b); 
} 

Then, run the program in debug mode and the output is as follows:

i   =   10 
i   =   32 

Then, run the program in release mode and the output is as follows:

i   =   10 
i   =   10 

The output clearly shows that the compiler optimized the code in release mode and did not print the correct I value the second time.
Now, let's take     Add the volatile keyword to the I declaration and see what happens:

#include   <stdio.h> 
void   main() 
{ 
  volatile   int   i=10; 
  int   a   =   i; 
  printf( "i=   %dn ",a); 
  __asm   { 
    mov                   dword   ptr   [ebp-4],   20h 
  } 
  int   b   =   i; 
  printf( "i=   %dn ",b); 
} 

Run the program in the debug version and the release version respectively, and the output is:
The same code at the page code block index 4 This shows that the keyword is working!


Related articles: