A variable defined as volatile means that the variable may be changed unexpectedly, so the compiler will not make assumptions about the value of the variable. To be precise, the optimizer must carefully re-read the value of the variable each time it is used, rather than using the copy stored in the register. Here are some examples of volatile variables:
1). Hardware registers of parallel devices (such as status registers)
2). Non-automatic variables accessed in an interrupt service subroutine
3). Variables shared by several tasks in a multithreaded application
Those who cannot answer this question will not be hired. I think this is the most basic question that distinguishes C programmers from embedded system programmers. Embedded system programmers often deal with hardware, interrupts, RTOS, etc., all of which require volatile variables. Not understanding the content of volatile will bring disaster.
Assuming the interviewee answers this question correctly (hmm, doubt it), I would dig a little deeper to see if this guy really understands the importance of volatile.
1). Can a parameter be both const and volatile? Explain why.
2). Can a pointer be volatile? Explain why.
3). What is wrong with the following function:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
Here are the answers:
1). Yes. An example is a read-only status register. It is volatile because it can be changed unexpectedly. It is const because the program should not attempt to modify it.
2). Yes. Although this is not very common. An example is when a service routine modifies a pointer to a buffer.
3). There is a trick in this code. The purpose of this code is to return the square of the value pointed to by pointer *ptr. However, since *ptr points to a volatile parameter, the compiler will generate code similar to the following:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
Since the value of *ptr may be changed unexpectedly, a and b may be different. As a result, this code may not return the square value you expect! The correct code is as follows:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
Let me share my understanding: (You are welcome to criticize me...~~!)
The key lies in two places:
1. Compiler optimization (please help me understand the following)
In this thread, when reading a variable, in order to improve access speed, the compiler sometimes reads the variable into a register first during optimization; later, when getting the variable value, it directly gets the value from the register;
When the variable value is changed in this thread, the new value of the variable will be copied to the register at the same time to keep it consistent
When the value of a variable is changed by another thread, the value of the register will not change accordingly, causing the value read by the application to be inconsistent with the actual variable value.
When the register value is changed by another thread, the value of the original variable will not change, causing the value read by the application to be inconsistent with the actual variable value.
Here is an inaccurate example:
When distributing salaries, the accountant always called employees to register their bank card numbers. One time, the accountant did not register immediately to save time and used the previously registered bank card number. It happened that an employee's bank card was lost and the bank card number had been reported lost. As a result, the employee could not receive his salary.
Employee -- Original variable address
Bank card number - backup of the original variable in the register
2. Under what circumstances will it appear (as mentioned in the first post)
1). Hardware registers of parallel devices (such as status registers)
2). Non-automatic variables accessed in an interrupt service subroutine
3). Variables shared by several tasks in a multithreaded application
Supplement: Volatile should be interpreted as "directly accessing the original memory address". The interpretation of "volatile" is a bit misleading.
"Volatile" is caused by external factors, such as multithreading, interrupts, etc. It does not mean that the variable modified with volatile is "volatile". If there is no external factor, it will not change even if it is defined with volatile.
After defining it with volatile, the variable will not change due to external factors and can be used with confidence. Let's see if the previous explanation (volatile) is misleading.
-------------A brief example is as follows:------------------
The volatile keyword is a type modifier that indicates that the type variable declared with it can be changed by some unknown factors of the compiler, such as the operating system, hardware, or other threads. When encountering a variable declared with this keyword, the compiler will no longer optimize the code that accesses the variable, thereby providing stable access to special addresses.
Examples of using this keyword are as follows:
int volatile nVint;
>>>>When the value of a variable declared with volatile is requested, the system always re-reads the data from the memory where it is located, even if the previous instruction has just read the data from there. And the read data is saved immediately.
For example:
volatile int i=10;
int a = i;
...
//Other codes do not explicitly tell the compiler that operations have been performed on i
int b = i;
>>>>volatile indicates that i may change at any time. Each time it is used, it must be read from the address of i. Therefore, the assembly code generated by the compiler will re-read the data from the address of i and put it in b. The optimization method is that since the compiler finds that the code between the two reads from i has not operated on i, it will automatically put the last read data in b. Instead of re-reading from i. In this way, if i is a register variable or represents a port data, it is easy to make mistakes, so volatile can ensure stable access to special addresses.
>>>>Note that in vc6, the general debugging mode does not perform code optimization, so the effect of this keyword cannot be seen. The following inserts assembly code to test the impact of the volatile keyword 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:
>>
#include
-------------------------------------------------
The variable corresponding to volatile may change without your program knowing.
For example, in a multi-threaded program, multiple programs can manipulate the variable in the shared memory.
Your own program cannot determine when the variable will change.
For example, it corresponds to a certain state of an external device. When the external device operates, the system changes the value of the variable through the driver and interrupt events, but your program does not know.
For volatile variables, the system directly extracts them from the corresponding memory every time it uses them, instead of using the original value in the cache to adapt to the unknown changes that may occur. The system will not optimize the processing of such variables - obviously because its value may change at any time.
-------------------------------------------------- ----------------------------------
A typical example
is for ( int i=0; i<100000; i++);
This statement is used to test the speed of an empty loop,
but the compiler will definitely optimize it and not execute it at all.
If you write
for ( volatile int i=0; i<100000; i++);
it will execute.
The original meaning of volatile is "volatile".
Since register access is faster than RAM, compilers generally optimize to reduce access to external RAM. For example:
static int i=0;
int main(void)
{
...
while (1)
{
if (i) dosomething();
}
}
/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}
The original intention of the program is to call the dosomething function in main when the ISR_2 interrupt occurs. However, since the compiler determines that i has not been modified in the main function, it
may only execute the read operation from i to a certain register once, and then each if judgment only uses the "copy of i" in this register, resulting in dosomething never being
called. If the variable is modified with volatile, the compiler guarantees that the read and write operations of this variable will not be optimized (definitely executed). The same should be said for i in this example.
Generally speaking, volatile is used in the following places:
1. Variables modified in the interrupt service program for detection by other programs need to be added with volatile;
2. Flags shared between tasks in a multitasking environment should be added with volatile;
3. Memory-mapped hardware registers usually also need to be declared volatile, because each read or write to them may have a different meaning;
In addition, the above situations often require the consideration of data integrity (several interrelated flags are interrupted and rewritten halfway through reading). In 1, this can
be achieved , in 2, task scheduling can be disabled, and in 3, only good hardware design can be relied upon.
Previous article:Correct usage of watchdog
Next article:Solve the problem of red cross in keil5 (compilation passed)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- LSM6DSOX iNEMO 6DoF Inertial Measurement Unit (IMU) Related Information
- Design of the tri-state logic pen
- Analysis of the Causes of TMS320C6000 Boot Failure
- EEWORLD University Hall----Live Replay: ST60 Contactless Connector and Application Exploration
- Difference between auto register static const volatile in C language
- How does a microcontroller collect analog signals through an ADC module?
- MM32W Wireless MCU Series Product Application Notes - Smart Colorful Remote Control Light Solution
- [NXP Rapid IoT Review] Part 1: Unboxing - Open Rapid IoT to see what the weather is like?
- High Accuracy Split-Phase CT Fuel Gauge Reference Design with Independent ADC
- EEWORLD University Hall----Mentor Expedition VX2.3 four-layer Bluetooth product