tags:

views:

9693

answers:

10

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

+7  A: 

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.

Chris Jester-Young
+3  A: 

Hi. volatile in C actually came into existence for the purpose of not cacheing the values of the variable automatically. It will tell the machine not to cache the value of this variable. So it will 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.

Manoj Doubts
+31  A: 

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

There is only one reason to use it: When you interface with hardware.

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 variales 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;
}
Nils Pipenbrinck
Personally, I'd prefer the integer size to be explicity e.g. int8/int16/int32 when talking to hardware. Nice answer though ;)
tonylo
yes, you should declare things with a fixed register size, but hey - it's just an example.
Nils Pipenbrinck
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.
tolomea
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.
ephemient
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.
tolomea
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.
Jonathan Leffler
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.
bta
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.
David Thornley
If you use volatile for concurrency instead of atomic variables or mutexes, you better know really well what you are doing.
ninjalj
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.
ninjalj
A: 

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.

Ori Pessach
A: 

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

Diomidis Spinellis
+5  A: 

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

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.

CesarB
A: 

it does not allows compiler to automatic changing values of variables. a volatile variable is for dynamic use.

venu
+1  A: 

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 precision which can ruin the computation of the derivative. 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.

Alexandre C.
+1  A: 

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.

Robert S. Barnes
@Robert S. Barnes: 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.
supercat
@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.
Robert S. Barnes
@Robert S. Barnes: 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.
supercat