601

Why is volatile needed in C? What is it used for? What will it do?

4

19 Answers 19

663

volatile tells the compiler not to optimize anything that has to do with the volatile variable.

There are at least three common reasons to use it, all involving situations where the value of the variable can change without action from the visible code:

  • When you interface with hardware that changes the value itself
  • when there's another thread running that also uses the variable
  • when there's a signal handler that might change the value of the variable.

Let's say you have a little piece of hardware that is mapped into RAM somewhere and that has two addresses: a command port and a data port:

typedef struct { int command; int data; int isBusy; } MyHardwareGadget; 

Now you want to send some command:

void SendCommand(MyHardwareGadget* gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isBusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; } 

Looks easy, but it can fail because the compiler is free to change the order in which data and commands are written. This would cause our little gadget to issue commands with the previous data-value. Also take a look at the wait while busy loop. That one will be optimized out. The compiler will try to be clever, read the value of isBusy just once and then go into an infinite loop. That's not what you want.

The way to get around this is to declare the pointer gadget as volatile. This way the compiler is forced to do what you wrote. It can't remove the memory assignments, it can't cache variables in registers and it can't change the order of assignments either

This is the correct version:

void SendCommand(volatile MyHardwareGadget* gadget, int command, int data) { // wait while the gadget is busy: while (gadget->isBusy) { // do nothing here. } // set data first: gadget->data = data; // writing the command starts the action: gadget->command = command; } 
Sign up to request clarification or add additional context in comments.

20 Comments

Personally, I'd prefer the integer size to be explicity e.g. int8/int16/int32 when talking to hardware. Nice answer though ;)
yes, you should declare things with a fixed register size, but hey - it's just an example.
Volatile is also needed in threaded code when you are playing with data that isn't concurrency protected. And yes there are valid times to be doing that, you can for example write a thread safe circular message queue without needing explicit concurrency protection, but it will need volatiles.
Read the C specification harder. Volatile only has defined behavior on memory-mapped device I/O or memory touched by an asynchronous interrupting function. It says nothing about threading, and a compiler which optimizes away access to memory touched by multiple threads is conformant.
@tolomea : completely wrong. sad 17 persons don't know it. volatile is not a memory fence. it is only related to avoiding code elision during optimization based on assumption of non visible side effects.
|
266

volatile in C actually came into existence for the purpose of not caching the values of the variable automatically. It will tell the compiler not to cache the value of this variable. So it will generate code to take the value of the given volatile variable from the main memory every time it encounters it. This mechanism is used because at any time the value can be modified by the OS or any interrupt. So using volatile will help us accessing the value afresh every time.

10 Comments

Came into existence? Wasn't ´volatile` originally borrowed from C++? Well, I seem to remember...
This is not volatile all about - it also prohibit some reordering if specified as volatile..
@FaceBro: The purpose of volatile was to make it possible for compilers to optimize code while still allowing programmers to achieve the semantics that would be achieved without such optimizations. The authors of the Standard expected that quality implementations would support whatever semantics were useful given their target platforms and application fields, and didn't expect that compiler writers would seek to offer the lowest quality semantics that conform to the Standard and weren't 100% stupid (note that the authors of the Standard explicitly recognize in the rationale...
...that it's possible for an implementation to be conforming without being of good enough quality to actually be suitable for any purpose, but they didn't think it necessary to prevent that).
@syntaxerror how can it be borrowed from C++ when C was more than a decade older than C++ (both on first releases and first standards)?
|
238

Another use for volatile is signal handlers. If you have code like this:

int quit = 0; while (!quit) { /* very small loop which is completely visible to the compiler */ } 

The compiler is allowed to notice the loop body does not touch the quit variable and convert the loop to a while (true) loop. Even if the quit variable is set on the signal handler for SIGINT and SIGTERM; the compiler has no way to know that.

However, if the quit variable is declared volatile, the compiler is forced to load it every time, because it can be modified elsewhere. This is exactly what you want in this situation.

9 Comments

when you say "the compiler is forced to load it every time, is it like when compiler decide to optimize a certain variable and we don't declare the variable as volatile, at run time that certain variable is loaded to CPU registers not in memory?
@AmitSinghTomar It means what it says: Every time the code checks the value, it is reloaded. Otherwise, the compiler is allowed to assume that functions that don't take a reference to the variable can't modify it, so assuming as CesarB intended that the above loop does not set quit, the compiler can optimise it into a constant loop, assuming that there's no way for quit to be changed between iterations. N.B.: This isn't necessarily a good substitute for actual threadsafe programming.
if quit is a global variable, then the compiler shall not optimize the while loop, correct ?
@PierreG. No, the compiler can always assume that the code is single-threaded, unless told otherwise. That is, in the absence of volatile or other markers, it will assume that nothing outside the loop modifies that variable once it enters the loop, even if it's a global variable.
@PierreG. Yes, try for instance compiling extern int global; void fn(void) { while (global != 0) { } } with gcc -O3 -S and look at the resulting assembly file, on my machine it does movl global(%rip), %eax; testl %eax, %eax; je .L1; .L4: jmp .L4, that is, an infinite loop if the global is not zero. Then try adding volatile and see the difference.
|
74

volatile tells the compiler that your variable may be changed by other means, than the code that is accessing it. e.g., it may be a I/O-mapped memory location. If this is not specified in such cases, some variable accesses can be optimised, e.g., its contents can be held in a register, and the memory location not read back in again.

1 Comment

changed particularly by hardware or other programs / drivers, and when this is intentional behaviour, you make it volatile to inform the compiler not to optimise out accesses to the memory address
37

See this article by Andrei Alexandrescu, "volatile - Multithreaded Programmer's Best Friend"

The volatile keyword was devised to prevent compiler optimizations that might render code incorrect in the presence of certain asynchronous events. For example, if you declare a primitive variable as volatile, the compiler is not permitted to cache it in a register -- a common optimization that would be disastrous if that variable were shared among multiple threads. So the general rule is, if you have variables of primitive type that must be shared among multiple threads, declare those variables volatile. But you can actually do a lot more with this keyword: you can use it to catch code that is not thread safe, and you can do so at compile time. This article shows how it is done; the solution involves a simple smart pointer that also makes it easy to serialize critical sections of code.

The article applies to both C and C++.

Also see the article "C++ and the Perils of Double-Checked Locking" by Scott Meyers and Andrei Alexandrescu:

So when dealing with some memory locations (e.g. memory mapped ports or memory referenced by ISRs [ Interrupt Service Routines ] ), some optimizations must be suspended. volatile exists for specifying special treatment for such locations, specifically: (1) the content of a volatile variable is "unstable" (can change by means unknown to the compiler), (2) all writes to volatile data are "observable" so they must be executed religiously, and (3) all operations on volatile data are executed in the sequence in which they appear in the source code. The first two rules ensure proper reading and writing. The last one allows implementation of I/O protocols that mix input and output. This is informally what C and C++'s volatile guarantees.

8 Comments

Does the standard specify whether a read is considered 'observable behavior' if the value is never used? My impression is that it should be, but when I claimed it was elsewhere someone challenged me for a citation. It seems to me that on any platform where a read of a volatile variable could conceivably have any effect, a compiler should be required generate code that performs every indicated read precisely once; without that requirement, it would be difficult to write code which generated a predictable sequence of reads.
"the compiler is not permitted to cache it in a register" - Most RISC arcitectures ae register-machines, so any read-modify-write has to cache the object in a registers. volatile does not guarantee atomicity.
@Olaf: Loading something into a register is not the same thing as caching. Caching would affect the number of loads or stores or their timing.
@Olaf: The Standard makes no attempt to specify what volatile behavior would be necessary to make an implementation suitable for any particular purpose, such as programming a particular real machine. Instead, it expects implementers to recognize the ways in which the real target machine may differ from the abstract one, and thus recognize what semantics users of particular platforms will need and give it to them. On a hardware platform where a load or store may trigger actions that affect program execution, a quality implementation should treat such actions as...
...though they could calls unknown functions [since they very well might], but the authors of gcc and clang seem to think that since such things don't happen on the "abstract machine", there's no reason they should allow for such possibilities when targeting a real one.
|
35

My simple explanation is:

In some scenarios, based on the logic or code, the compiler will do optimisation of variables which it thinks do not change. The volatile keyword prevents a variable being optimised.

For example:

bool usb_interface_flag = 0; while(usb_interface_flag == 0) { // execute logic for the scenario where the USB isn't connected } 

From the above code, the compiler may think usb_interface_flag is defined as 0, and that in the while loop it will be zero forever. After optimisation, the compiler will treat it as while(true) all the time, resulting in an infinite loop.

To avoid these kinds of scenarios, we declare the flag as volatile, we are telling to compiler that this value may be changed by an external interface or other module of program, i.e., please don't optimise it. That's the use case for volatile.

Comments

21

A marginal use for volatile is the following. Say you want to compute the numerical derivative of a function f :

double der_f(double x) { static const double h = 1e-3; return (f(x + h) - f(x)) / h; } 

The problem is that x+h-x is generally not equal to h due to roundoff errors. Think about it : when you substract very close numbers, you lose a lot of significant digits which can ruin the computation of the derivative (think 1.00001 - 1). A possible workaround could be

double der_f2(double x) { static const double h = 1e-3; double hh = x + h - x; return (f(x + hh) - f(x)) / hh; } 

but depending on your platform and compiler switches, the second line of that function may be wiped out by a aggressively optimizing compiler. So you write instead

 volatile double hh = x + h; hh -= x; 

to force the compiler to read the memory location containing hh, forfeiting an eventual optimization opportunity.

5 Comments

What is a difference between using h or hh in derivative formula? When hh is computed the last formula uses it like the first one, with no difference. Maybe it should be (f(x+h) - f(x))/hh?
The difference between h and hh is that hh is truncated to some negative power of two by the operation x + h - x. In this case, x + hh and x differ exactly by hh. You can also take your formula, it will give the same result, since x + h and x + hh are equal (it is the denominator which is important here).
Isn't more readable way to write this would be x1=x+h; d = (f(x1)-f(x))/(x1-x)? without using the volatile.
Any reference that a compiler can wipe out that second line of the function?
@CoffeeTableEspresso : Nope, sorry. The more I know about floating point, the more I believe that the compiler is only allowed to optimize it if explicitely told so, with -ffast-math or equivalent.
11

I'll mention another scenario where volatiles are important.

Suppose you memory-map a file for faster I/O and that file can change behind the scenes (e.g. the file is not on your local hard drive, but is instead served over the network by another computer).

If you access the memory-mapped file's data through pointers to non-volatile objects (at the source code level), then the code generated by the compiler can fetch the same data multiple times without you being aware of it.

If that data happens to change, your program may become using two or more different versions of the data and get into an inconsistent state. This can lead not only to logically incorrect behavior of the program but also to exploitable security holes in it if it processes untrusted files or files from untrusted locations.

If you care about security, and you should, this is an important scenario to consider.

Comments

11

There are two uses. These are specially used more often in embedded development.

  1. The compiler will not optimise the functions that use variables that are defined with the volatile keyword

  2. Volatile is used to access exact memory locations in RAM, ROM, etc... This is used more often to control memory-mapped devices, access CPU registers and locate specific memory locations.

See examples with assembly listing. Re: Usage of C "volatile" Keyword in Embedded Development

2 Comments

"Compiler will not optimise the functions that uses variables that are defined with volatile keyword" - that's plain wrong.
Additionally, volatile can be used to force memory reads or writes to be a particular size. For example, there can be 8-bit only memory, or 16-bit only memory, and a read or write of the wrong type will have an undesirable effect. Without volatile, the compiler is free to combine four 8-bit writes into a 32-bit write, even if the memory does not support that kind of write. There are even cases where a for loop gets changed into memset which attempts to write bytes to 16-bit only memory, but this disappears when using volatile.
10

Volatile is also useful, when you want to force the compiler not to optimize a specific code sequence (e.g. for writing a micro-benchmark).

Comments

10

In my opinion, you should not expect too much from volatile. To illustrate, look at the example in Nils Pipenbrinck's highly-voted answer.

I would say, his example is not suitable for volatile. volatile is only used to: prevent compiler optimizations that would normally be useful and desirable. It is nothing about thread safety, atomic access or even memory order.

In that example:

 void SendCommand (volatile MyHardwareGadget * gadget, int command, int data) { // Wait while the gadget is busy: while (gadget->isbusy) { // Do nothing here. } // Set data first: gadget->data = data; // Writing the command starts the action: gadget->command = command; } 

The gadget->data = data before gadget->command = command only is only guaranteed in the compiled code by the compiler.

At run time, the processor may still reorder the data and command assignment, depending on the processor architecture. The hardware could get the wrong data (suppose a gadget is mapped to hardware I/O). A memory barrier is needed between data and command assignment.

Comments

9

In the language designed by Dennis Ritchie, every access to any object, other than automatic objects whose address had not been taken, would behave as though it computed the address of the object and then read or wrote the storage at that address. This made the language very powerful, but severely limited optimization opportunities.

While it might have been possible to forbid compilers from assuming that addressable objects would never be changed in weird ways, such an assumption would have been appropriate and useful for the vast majority of objects in C programs, and it would have been impractical to add a qualifier to all the objects for which such assumption would be appropriate. On the other hand, some programs need to use some objects for which such an assumption would not hold. To resolve this issue, the Standard says that compilers may assume that objects which are not declared volatile will not have their value observed or changed in ways that are outside the compiler's control, or would be outside a reasonable compiler's understanding.

Because various platforms may have different ways in which objects could be observed or modified outside a compiler's control, it is appropriate that quality compilers for those platforms should differ in their exact handling of volatile semantics. Unfortunately, because the Standard failed to suggest that quality compilers intended for low-level programming on any particular platform should handle volatile in a way that will recognize any and all relevant effects of a particular read/write operation on that platform, many compilers fall short of doing so in ways that make it harder to process things like background I/O in a way which is efficient but can't be broken by compiler "optimizations".

Comments

7

volatile means the storage is likely to change at any time and be changed by something outside the control of the user program.

This means that if you reference the variable, the program should always check the physical address (i.e., a mapped input FIFO), and not use it in a cached way.

1 Comment

No compiler takes volatile to mean either "physical address in RAM" or "bypass the cache".
6

In simple terms, it tells the compiler not to do any optimisation on a particular variable. Variables which are mapped to device register are modified indirectly by the device. In this case, volatile must be used.

1 Comment

Is there anything new in this answer which has not been mentioned before?
5

Wikipedia says everything about volatile:

And the Linux kernel's documentation also makes a excellent note about volatile:

Comments

3

A volatile can be changed from outside the compiled code (for example, a program may map a volatile variable to a memory mapped register).

The compiler won't apply certain optimizations to code that handles a volatile variable. For example, it won't load it into a register without writing it to memory. This is important when dealing with hardware registers.

Comments

3

Volatile is often misunderstood as "disabling optimizations," synchronizing access to a variable, or generating memory fences. None are entirely the case. All it does is disable any compiler optimizations that assume the variable has not changed from an outside context.

What Volatile Does According to GCC

Eliminating Opimizations Effect

To understand volatile, we can simply look at the code generated by GCC. In the first example we will multiply the volatile variable with argc and store in i.

volatile int i = 0; int main(int argc, char **argv) { i *= argc; return 0; } 

See assembly here with O2: https://godbolt.org/z/cf4KGjxvP

main: mov eax, DWORD PTR i[rip] add eax, 1 mov DWORD PTR i[rip], eax xor eax, eax ret i: .zero 4 

Volatile tells the compiler that the variable cannot be expected at compile time to have remained the same between accesses. It could change at any point during execution. The compiler is told to disable dead store elimination since doing so could lead to unexpected behavior.

Referencing the variable without doing anything to it also generates a load. https://godbolt.org/z/z9cffTsqb

Basically, the compiler disables any optimization that eliminates loads or stores.

Is It A Fence? On GCC, Yes.

On GCC, volatile appears to act as a compiler fence. This code:

volatile int i,j,k,l; int main(int argc, char **argv) { i += j + k + l; } 

When the order of the addition is changed, the corresponding assembly has a different load order. See: https://godbolt.org/z/z9KG3PnbE

So on GCC, volatile is a compiler memory fence, but no fence instructions are generated to serialize access.

On MSVC, the same sample was generated with the loads in reverse, but changing the variable order did also affect the load order. MSVC also regards it as a compiler fence. https://godbolt.org/z/snWz6fYa6

What Volatile Does Not Do

Volatile is not a memory fence. The compiler could treat it as one, but there is no guarantee. It is free to reorder memory accesses as long as it does not eliminate them. That means if you really need a memory access to happen between two function calls, it may not be generated that way.

Instead, a compiler or real memory fence must be explicitly used. Concurrent access between multiple processors may not work unless controlled with a lock or fence.

Volatile does not ensure atomicity. The loads and stores will happen with single instructions, but atomic operations may not be used. In the first example, the number was incremented with a single operation.

Conclusion

Volatile provides very few guarantees about the behavior of the variable. It should be considered non-portable for any situation outside its very narrow scope. Volatile variable access should be encapsulated inside helper functions and volatile function parameters or returns should be avoided.

The situations where volatile should be used are:

  • Memory mapped IO registers
  • Signal handler variables
  • Interrupt service routine variables (for example, waiting in a loop until device gives "ready" signal)
  • Testing the effectiveness of optimization on a single variable

Multithreaded programming should never include volatile since acquiring a critical section for a variable ensures that within it all optimizations are allowed because nothing else can access the variable.

1 Comment

On implementations designed to be to support low-level programming without requiring compiler-specific syntax, a volatile access will be act as a global barrier against compiler reordering, but so far as I can tell the only way to configure clang and gcc to reliably work that way without using special syntax is -O0.
-1

As rightly suggested by many here, the volatile keyword's popular use is to skip the optimisation of the volatile variable.

The best advantage that comes to mind, and worth mentioning after reading about volatile is -- to prevent rolling back of the variable in case of a longjmp. A non-local jump.

What does this mean?

It simply means that the last value will be retained after you do stack unwinding, to return to some previous stack frame; typically in case of some erroneous scenario.

Since it'd be out of scope of this question, I am not going into details of setjmp/longjmp here, but it's worth reading about it; and how the volatility feature can be used to retain the last value.

1 Comment

Re "out of scope of this question": No, please provide a code example.
-4

It does not allow the compiler to automatically change values of variables. A volatile variable is for dynamic use.

Comments