Why is volatile needed in C?
Asked Answered
M

19

566

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

Mascot answered 29/10, 2008 at 8:36 Comment(4)
https://mcmap.net/q/15519/-why-does-volatile-existLabelle
Related: When to use volatile with multi threading? applies to C11 and later as well. It's not needed for that, but was used until C11 gave a fully standardized way to do lock-free atomic load/store.Hooknosed
Similar for C# and Java: What is the "volatile" keyword used for?Valuate
An even earlier one (2008-09-16): Why does volatile exist?Valuate
L
616

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;
}
Litmus answered 29/10, 2008 at 8:45 Comment(20)
Personally, I'd prefer the integer size to be explicity e.g. int8/int16/int32 when talking to hardware. Nice answer though ;)Kalimantan
yes, you should declare things with a fixed register size, but hey - it's just an example.Litmus
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.Burkle
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.Kevinkevina
Do you have a reference for that claim? Every reference I've seen says volatile tells the compiler not to optimize memory accesses on whatever. I've never seen a restriction on whether the memory is RAM or IO. Further on many platforms the compiler can't distinguish between RAM and memory mapped IO.Burkle
In signal handlers, one of the few things it is truly safe to do is set a global variable of the type 'volatile sigatomic_t'. Also, where setjmp() is used, you should worry about which local variables are marked volatile.Adverb
Instead of saying volatile is used "when you interface with hardware", I would say "when the variable can be altered by something outside of your program". This covers the memory-mapped hardware case as well as shared memory, etc.Naked
I'm not as familiar with C, but in C++ volatile memory accesses are defined as observable behavior, and therefore have to be executed as written and without any reordering. That will apply to shared memory in threaded code as well as memory-mapped I/O.Turley
If you use volatile for concurrency instead of atomic variables or mutexes, you better know really well what you are doing.Prothorax
To explain better what Jonathan Leffler said, variables local to the function that called setjmp() that have been changed between the setjmp() and longjmp() calls, have undefined values unless declared volatile.Prothorax
@DavidThornley, @tolomea: While the volatile memory access is defined as observable behaviour that has to be executed as written and without reordering, it's not defined that it's also performed atomically. Which it simply does not have to. That's why C++11 introduces the std::atomic types, which have stronger guarantees. See N2016 for discussion about volatile and threads (whitepaper from C++11 standardization process).Leahy
@JanHudec: And to clarify, they only have to maintain order between other volatile variables. They don't act as memory barriers.Carbine
@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.Prewitt
the answer is false in many ways, for example volatile variables do exist in registers. notably volatile is indeed useful on memory mapped registers. crazy this answer has 67 upvotes... The next wrong thing is the re-ordering guarantee, please read software.intel.com/en-us/blogs/2007/11/30/…Prewitt
@NilsPipenbrinck does volatile MyHardwareGadget * gadget declare the value pointed by gadget is volatile instead of the pointer? or I am wrong?Linebreeding
As others have commented, you forgot to mention another crucial use of the keyword, i.e: multi threaded programming. It will prevent the compiler from caching the marked variable by any means when it thinks it can do so based solely on the local vicinity of the code where that variable is used (think a shared counter or similar).Elegance
-1 Volatile does NOT guarantee ordering (e.g. "memory fence"). You must use something like std::atomic to achieve that, or rely on a compiler macro that will implement the hardware-specific memory fence behind the scenes.Echinoderm
"Volatile tells the compiler not to optimize anything that has to do with the volatile variable." the first line is already wrong.Durwin
How can one say that the "compiler caches a variable"? Isn't that the CPU:s job? The compiler has no active participation during run time ...Affectation
Abdel, you're confusing the CPU's caches, which cache RAM, and C variable caching. In this case, the compiler can cache a commonly-used variable in a CPU register. Particularly if the CPU has a lot of registers available, ARM chips being an example of that. If the compiler thinks it can speed up some code by putting an often-accessed variable in a register, it often will. If some other hardware or software is expecting the variable to be read / written from a RAM location, and code is ignoring it, instead using a register, then problems can happen.Michelle
S
254

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.

Slalom answered 29/10, 2008 at 8:44 Comment(10)
Came into existence? Wasn't ´volatile` originally borrowed from C++? Well, I seem to remember...Lilley
This is not volatile all about - it also prohibit some reordering if specified as volatile..Kendakendal
@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...Ganley
...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).Ganley
@Lilley how can it be borrowed from C++ when C was more than a decade older than C++ (both on first releases and first standards)?Mussorgsky
How can one say that the "compiler caches a variable"? Isn't that the CPU:s job? The compiler has no active participation during run time ...Affectation
Volatile will prevent the compiler from optimizing out a load or a store, but it will not prevent the cache line containing the field being accessed, from being cached. Mechanisms like PAT and MTTR are needed for that to make a page or a region of memory uncachable.Ellery
That should be MTRR.Ellery
MTRR = memory type range registerValuate
PAT = page attribute tableValuate
S
230

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.

Silicify answered 29/10, 2008 at 10:52 Comment(9)
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?Suppository
@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.Pillage
if quit is a global variable, then the compiler shall not optimize the while loop, correct ?Vivyanne
@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.Silicify
thx CesarB. so in that case, can the compiler optimize a while like this : while(gloval_variable <> 0) {} and make this loop lock forever ?Vivyanne
@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.Silicify
@Silicify In practice, if the body of the loop is non trivial and calls external functions, and if the flag is a global variable, then the compiler will probably assume that the call to functions can change the variable.Catalectic
How can one say that the "compiler loads a variable"? Isn't that the CPU:s job? The compiler has no active participation during run time ...Affectation
Another thing I can't quite wrap my head around: I guess the 'quit' variable is non-stack, i.e. global. It is probably referenced in an ISR right? Can't the compiler understand that it is being assigned in that ISR and is hence (potentially) modified by the visible code (so volatile qualifier becomes unnecessary)?Affectation
K
71

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.

Kolnos answered 29/10, 2008 at 8:41 Comment(1)
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 addressCatlaina
K
36

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.

Klara answered 22/7, 2010 at 12:33 Comment(8)
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.Ganley
@supercat: According to the first article, "If you use the volatile modifier on a variable, the compiler won't cache that variable in registers — each access will hit the actual memory location of that variable." Also, in section §6.7.3.6 of the c99 standard it says: "An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects." It further implies that volatile variables may not be cached in registers and that all reads and writes must be executed in order relative to sequence points, that they are in fact observable.Klara
The latter article indeed states explicitly that reads are side-effects. The former indicates that reads cannot be performed out of sequence, but did not seem to preclude the possibility of them being elided altogether.Ganley
"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.C
@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.Ganley
@supercat: I seem to have completely missed caching disallows to not prevent loads/stores. Anyway, I should have used a better term here indeed. If I just knew one. Nevertheless it should be clear from the context what I mean. Plus there is no guarantee a volatile is not held in a register. In fact the abstract machine allows a lot of optimisations even for volatiles.C
@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...Ganley
...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.Ganley
L
32

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.

Lockman answered 24/1, 2015 at 7:1 Comment(0)
E
20

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.

Engenia answered 30/6, 2010 at 11:34 Comment(5)
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?Slaw
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).Engenia
Isn't more readable way to write this would be x1=x+h; d = (f(x1)-f(x))/(x1-x)? without using the volatile.Slaw
Any reference that a compiler can wipe out that second line of the function?Sadden
@Sadden : 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.Engenia
S
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

Sadness answered 30/7, 2011 at 4:59 Comment(2)
"Compiler will not optimise the functions that uses variables that are defined with volatile keyword" - that's plain wrong.C
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.Gentry
A
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.

Atalie answered 26/11, 2011 at 10:5 Comment(0)
G
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).

Gerena answered 29/10, 2008 at 8:46 Comment(0)
S
9

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.

Subkingdom answered 14/3, 2016 at 15:26 Comment(1)
I'd say volatile is used to prevent the compiler from making optimizations that would normally be useful and desirable. As written, it sounds like volatile is degrading the performance for no reason. As for whether it is sufficient, that will depend upon other aspects of the system that the programmer may know more about than the compiler. On the other hand, if a processor guarantees that an instruction to write to a certain address will flush the CPU cache but a compiler provided no way to flush register-cached variables the CPU knows nothing about, flushing the cache would be useless.Ganley
G
8

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".

Ganley answered 13/7, 2018 at 22:28 Comment(2)
The sentence starting with "While it might have" does not read well. For instance, do you mean "such an assumption would be inappropriate"? Perhaps rephrase?Valuate
@PeterMortensen: Yeah, that was a bit of a jumbly mess. Hopefully it's better now.Ganley
L
6

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.

Latonya answered 9/7, 2011 at 3:14 Comment(1)
No compiler takes volatile to mean either "physical address in RAM" or "bypass the cache".Catalectic
N
5

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.

Nichy answered 22/10, 2018 at 17:34 Comment(1)
Is there anything new in this answer which has not been mentioned before?Curricle
W
4

Wikipedia says everything about volatile:

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

Wedding answered 5/9, 2012 at 14:54 Comment(0)
R
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.

Reeding answered 29/10, 2008 at 8:45 Comment(0)
H
1

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.

Herculean answered 6/12, 2023 at 4:47 Comment(0)
A
0

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.

Abbotsun answered 8/12, 2019 at 12:16 Comment(1)
Re "out of scope of this question": No, please provide a code example.Valuate
R
-4

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

Rewarding answered 21/5, 2010 at 19:23 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.