Volatile means "easy to lose, easy to change ". The definition of this qualifier indicates to the compiler that the content of the variable may change due to modifications to other programs. When a variable is declared in a program, the compiler tries its best to store it in General registers, such as ebx. When the CPU puts the value in ebx, it no longer cares about the value in the corresponding memory. If another program (such as a kernel program or an interrupt) modifies its value in the memory, the value in ebx will not be updated accordingly. To solve this problem, a volatile qualifier is created, so that the Code must obtain the value from the specified position when referencing the variable.
What does the keyword volatile mean? Three different examples are provided. A variable defined as volatile means that this variable may be unexpectedly changed, so that the compiler will not assume the value of this variable. Precisely, the optimizer must carefully re-read the value of this variable every time when using this variable, rather than using the backup stored in the register. The following are examples of volatile variables:
1). Hardware registers of parallel devices (for example, Status Registers)
2). Non-automatic variables that will be accessed in an interrupt service subroutine)
3) variables shared by several tasks in multi-threaded applications
People who cannot answer this question will not be hired. I think this is the most basic problem to distinguish between C programmers and embedded system programmers. Embedded System programmers often deal with hardware, interruptions, RTOS, and so on, all of which require volatile variables. If you do not know volatile content, it will lead to disasters.
If the subject correctly answers this question (well, I doubt this will happen), I will go a little deeper to see if this guy understands the full importance of volatile.
1) can a parameter be const or volatile? Explain why.
2) can a pointer be volatile? Explain why.
3) What are the following function errors:
Int square (volatile int * ptr)
{Return * ptr ** ptr ;}
The answer is as follows:
1). Yes. One example is read-only status registers. It is volatile because it may be unexpectedly changed. It is const because the program should not try to modify it.
2). Yes. Although this is not very common. One example is when a service subroutine repairs a pointer to a buffer.
3) This code has a prank. The purpose of this Code is to return the pointer * ptr points to the square of the value. However, since * ptr points to a volatile parameter, the compiler will generate code similar to the following:
Copy codeThe Code is as follows: int square (volatile int * ptr)
{
Int a, B;
A = * ptr;
B = * ptr;
Return a * B;
}
* The value of * ptr may be unexpectedly changed, so a and B may be different. As a result, this Code may not return the expected square value! The correct code is as follows:Copy codeCode: long square (volatile int * ptr)
{
Int;
A = * ptr;
Return a * ;}
Volatile is intended to be "changeable"
Since the speed of accessing registers is faster than that of RAM, the compiler generally reduces the access to external RAM. For example:Copy codeThe Code is as follows: static int I = 0;
Int main (void)
{
...
While (1)
{
If (I) dosomething ();
}
}
/* Interrupt service routine .*/
Void ISR_2 (void)
{
I = 1;
}
The program is intended to call the dosomething function in main when ISR_2 is interrupted. However, since the compiler judges that I has not been modified in the main function
The read operation from I to a register may be performed only once, and then only the "I copy" in this register is used for each if judgment, so that dosomething will never be called. If the variable is modified with volatile, the compiler ensures that the read and write operations on the variable are not optimized (certainly executed ). In this example, I should also describe this.
Generally, volatile is used in the following areas:
1. volatile must be added to the variable modified in the interrupted service program for testing by other programs;
2. volatile should be added to the labels shared by all tasks in a multi-task environment;
3. volatile is also required for the hardware registers mapped to memory, because each read/write to it may have different meanings;
In addition, in the above situations, we often need to consider data integrity at the same time (some of the correlated indicators have been read in half and are interrupted for rewriting). In 1, we can use the Guanzhong disconnection to implement
Task Scheduling can be disabled in 2, and in 3, it can only rely on the good design of hardware.
// ====================
The pointer type is also a variable, so it can be modified using volatile.
The volatile keyword is a type modifier that uses the type variables it declares to indicate that it can be changed by unknown factors of Some compilers, such
Operating system, hardware, or other threads. When the variable declared by this keyword is encountered, the compiler does not perform any operations on the code that accesses the variable.
Optimized to provide stable access to special addresses.
An example of using this keyword is as follows:
Int volatile nVint;
When the value of a variable declared by volatile is required, the system always reads data from its memory again, even if
So that data has just been read from this place. The read data is saved immediately.
For example:
Volatile int I = 10;
Int a = I;
... // Other code that does not explicitly tell the compiler to perform operations on I
Int B = I;
Volatile indicates that I may change at any time and must be read from the I address every time it is used. Therefore,
The Assembly Code will re-read data from the I address and put it in B. The optimization method is because the compiler finds that the Code reads data from I twice
The Code does not perform operations on I. It will automatically put the data read last time in B. Instead of reading from I again. In this case, if
I is a register variable or indicates that data on a port is prone to errors, so volatile can ensure stable access to special addresses.
Note: In vc6, the Code is not optimized in general debugging mode, so the function of this keyword cannot be seen. Insert the Assembly
Code to test whether the volatile keyword exists and the impact on the final code of the program:
First, use classwizard to create a win32 console project, insert a voltest. cpp file, and enter the following code:Copy codeThe Code is as follows: # include <stdio. h>
Void main ()
{
Int I = 10;
Int a = I;
Printf ("I = % d \ n", );
// The purpose of the following Assembly statement is to change the I value in the memory, but it does not let the compiler know
_ Asm {
Mov dword ptr [ebp-4], 20 h
}
Int B = I;
Printf ("I = % d \ n", B );
}
Then, run the program in debug version mode and the output result is as follows:Copy codeThe Code is as follows: I = 10
I = 32
Then, run the program in release version mode. The output result is as follows:Copy codeThe Code is as follows: I = 10
I = 10
The output results obviously show that in the release mode, the compiler optimizes the code and does not output the correct I value for the second time.
Next, we add the volatile keyword to the I statement to see what changes have taken place:Copy codeThe Code is as follows: # include <stdio. h>
Void main ()
{
Volatile int I = 10;
Int a = I;
Printf ("I = % d \ n", );
_ Asm {
Mov dword ptr [ebp-4], 20 h
}
Int B = I;
Printf ("I = % d \ n", B );
}
Run the program in the debug version and release version respectively, and the output is:Copy codeThe Code is as follows: I = 10
I = 32
This indicates that this keyword plays its role!