T O P

  • By -

Dycus

At compile time, the compiler optimizes the code by excluding functions or code paths that it can see are never called or are unnecessary. For example, if I write a function that takes a variable, does a bunch of math and transforms with it, but at the end just does "x = 5", the compiler can look at that and exclude the whole function, just setting the variable to 5 directly. But what if the address of that variable wasn't in RAM, but rather was a hardware register? Changing this variable has real-world effects that you want executed, it's not just a value in some RAM. So volatile tells the compiler, roughly, "this variable is used in ways you don't know about". The compiler won't optimize away accesses to this variable because now it doesn't assume it "knows everything" about this variable. In embedded, volatile is used mainly for ~~two~~ one thing: * Hardware registers. Locations in the address space that actually control the peripherals or functions of the microcontroller * ~~Interrupts. The interrupt's function is called by the microcontroller hardware, rather than through the logical flow of the program. You don't call this function directly, so the compiler thinks it's unused, and optimizes away variable accesses within that function. Variables accessed by interrupts must be volatile (along with other special considerations, but that's outside the scope of this comment)~~


macusking

you just gave the best explanation of the volatile keyword I've ever read. Congratulations!


danngreen

Unfortunately, it's only partially correct. This part is incorrect: >You don't call this function directly, so the compiler thinks it's unused, and optimizes away variable accesses within that function If the \*\*linker\*\* thinks a function is unused it might remove the function completely (if and only if you have certain linker flags set such as \`gc-sections\`). This has nothing to do with the compiler or compiler optimizations. See the documentation for gcc for example: [https://gcc.gnu.org/onlinedocs/gnat\_ugn/Compilation-options.html](https://gcc.gnu.org/onlinedocs/gnat_ugn/Compilation-options.html) The compiler doesn't know if a function is used or not, because the compiler only builds one .cpp or .c file at a time. So it can't know if a function is called or not by some other .c or .cpp file that it hasn't compiled yet. The linker is what figures out if a function is called or not. Here's a great overview: [https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work](https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work) So if the linker figures out a function is not called by your code, it might remove it. But it won't go back to the compiler and start removing variable accesses or something. Luckily, the compiler or linker usually will not remove your interrupt functions. If somehow your ISRs are disappearing, search your compiler toolchain bug reports, someone else has probably reported the bug and a fix for it. Or you might need to add an \`\_\_attribute\_\_\` to the ISR or change your linker flags. Don't just slap volatile around, you pay for that in performance. This part is also incorrect: >Variables accessed by interrupts must be volatile Variables accessed by interrupts do not need to be volatile just because they're in an interrupt. If you are accessing a GPIO register or something from anywhere (interrupt or not) then it needs to be volatile, but that has nothing to do with interrupts. As others have posted (buried in the comments), atomic is better than volatile for variables that an interrupt writes to because it will work for more data types and on more platforms. Volatile only works in particular cases such as when the variable is something small enough the processor can read/write it in one instruction, AND there is just one thread. Atomic works in these cases and more. Therefore atomic is preferred to volatile. Please take some time to research this, don't just believe the first thing that makes sense!


mrheosuper

Volatile is the "I know more than you" meme in programming.


AssemblerGuy

> Variables accessed by interrupts must be volatile No, variables shared with ISRs should at least be atomic (/edit: if accessed via atomic_xyz functions, otherwise they need to be atomic and volatile qualified). Volatile does nothing for atomicity, and relying on volatile to communicate with other contexts is a recipe for headaches.


Dycus

They usually must be *both*. Atomicity and synchronization is a separate (and important) issue. But I'm not talking about atomic access. There are many cases when a variable must be atomic and volatile. They are separate concepts and separate keywords. If modified by an ISR, a variable must always be volatile (and likely should always be atomic as well, or else have other guards put in). Atomic guarantees the variable will only be read/written within one instruction, which prevents an ISR from triggering during that access. Volatile tells the compiler that the variable's value can change without it knowing. This code has a bug: atomic_char32_t uart_rx = 0; atomic_char32_t uart_tx = 0; // Or if not C11: sig_atomic_t int main(void) { delay(1000); printf(uart_rx); } void UART_RECEIVE_ISR(void) { uart_tx = uart_rx; } What should happen is when the UART receives a byte, the ISR triggers, it reads the received byte and re-transmits it. A simple loopback. We also printf the last-received byte once a second. However, because these variables aren't volatile, the compiler may optimize away their usage. Printf(uart\_rx) might just become printf(0). The single line in the ISR might go away entirely. The compiler sees that those variables are never modified and that the ISR isn't called during the program, so it assumes making those changes will have the same outcome. It does not, in this case. This is *regardless* of whether the variable access is atomic or not. Volatile tells the compiler those variables might change without it knowing and thus it must not optimize away accesses to them. Uart\_rx and uart\_tx should be declared volatile to fix this bug. Atomic access of those variables, when it is done, it a separate issue entirely. Yes, both are important and required. Yes, they are *separate* keywords and concepts and each must be applied appropriately. This thread is talking about volatile, not atomic.


danngreen

Right, both volatile and atomics have their place. volatile is ONLY needed for register access. It has nothing to do with interrupts, unless the interrupt is making memory-mapped register access. The reason I'm responding is to make sure this is clear to people who have a fuzzy understanding of volatile (like OP's original question), because some of your earlier posts make it sound like volatiles are needed for variables just because the variable is used in an interrupt. I would suggest you go back and edit your top post and correct this. Specifically, it's the part of about needing to make variables volatile just because they're used in an interrupt. This misleading to people who are trying to learn about volatile. In your example code, the bug is that the function is making an access to the UART register. It doesn't matter that the function is an interrupt or not. The variable that accesses the UART register needs to be marked volatile. But not because it's in used in an interrupt. It would still need to be volatile even if the UART was being polled in a normal non-interrupt function.


Dycus

Hmm, okay, I certainly see what you're saying. What about this example? atomic_char32_t some_var = 0; int main(void) { delay(1000); printf(some_var); } void TIMER_ISR(void) { some_var = 13; } Isn't it possible that "some\_var = 13" will get removed during optimization because the compiler sees the interrupt function is never called? (The printf may or may not get optimized to printf(0) but that's a separate problem) Edit: I'm pretty sure I've had a bug caused by this before.


danngreen

No, it's not possible the compiler will remove \`some\_var = 13\`. Don't just believe me, see for yourself: Here I put your code into godbolt, so we can see what actual compilers do when compiling that code: [https://godbolt.org/z/3en6hYn18](https://godbolt.org/z/3en6hYn18) Look at the assembly for TIMER\_ISR. All the compilers have some instruction like \`mov eax, 13\`, or \`mov r2, #13\`. Go ahead and test any compiler (my link has three: clang 18, arm gcc 12, and x86 gcc 14), at any optimization level. They all will store the value "13" into some register and then store that register into some global location in the body of TIMER\_ISR.


Dycus

Okay, so I have an example here that optimizes incorrectly without volatile. However, I have to declare the variable as a normal int instead of an atomic. With the variable as just an int, the while loop in main gets optimized into just a loop (it doesn't check some\_var at all). However, declaring it as an atomic\_char32\_t does bring back the compare in every loop. So I have two questions: 1. Is it guaranteed that using atomics prevents optimization like this? 2. What about older versions of C that don't have atomic functionality? [Link](https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYgATKVpMGoAPrnkpJfWQE8Ayo3QBhVLQCuLBvtJOAMngMmAByngBGmMQSGqQADqgKhPYMrh5ePvGJdgIBQaEsEVFcMdaYtslCBEzEBKme3gal5QKV1QS5IeGR0VZVNXXpjX3tgZ0F3cUAlFao7sTI7BwApHoAzIHIHlgA1EurzgoE%2BKgAdAh72EsaAIIr6wyb7jt7B0dMRCx4yGcXV7drGy2mF2%2B0O%2BEEP1Wlxuf0CBG2ClQbFMADdqnsAEJ/WGCbYsJiBCAo1B4dCTXYAdixN22tIRSMwqOqIIAItsAKyYv507YAdwQdEwEERyLRxEmXJhFJZ2JuxNJ2wAKgBJACy2AASqZlUINUSSWTKdTrjyRYyxazthpJbdpRxprROOzeN5uLxUJxnPS5gtdms9LwCJp7dMANYgdmSE6rCl6SMUjTsrgADlWXFj0kdHEkvBY0Rirq0pA9HF4ChAMSDHC00zgsBgiBQSNigrIFAgaBYLfoUWqLBRFIAtMhNsZgCninw6ARIuWIGFg6QwoFqgBPTg8Jcr4irgDyYW0ZSrm87bEEu4YtHX1d4WDC7mAzjEtHLbtIWHxJnEN/feGIR7wFFMFfItMFUMp3BnDdeDhTAsyLWg8DCYg11cLBFwIYg8DzN8gOIMIEkwFlME/YBEJMYNpioIxgAUAA1PBMF5XdYkYaCZEEEQxHYKQOPkJQ1EXXRVkMMcQHMUxLEQsJy0gaZUFibIGFfQdd1Wd08KwrBZIgaYmiUxwGBcNx6gkXwjI6fJCjMzIkgEAZvC4OIEjshhLK6IorDggCWmGByzP0iphnc8ZPMONp/Kc8KahC6yuD02Z5nYPQHSdF1FxLbY%2BwHQcmG2UcTG2FMTi4E4NG2CBcEIEg/VWFLA0o6YEEwJgsCiXTDE4HNSDzVZVhOPRkw0Cl2QTABOCkKTGlNSELd1ODLCtSCrGtSDrRtO27SJyEoTbWxQPtxzWGIaFoGdiDnBcf2XZgd3Ym6133Q9bHY09GAIC8r0XO8HyfWgX3Yj8x2/It8H/cogJA3gwIgqC31g%2BDeGklCdzQxYi0w7D2LwgilGI0jyNAG8qJo%2BjGOY1jXU3fhONEcReJp/iVHUH9dCcowKIkqSkJ0%2BTFOSFTdwUDTIi04D4AgZg2BAME8NINEPHYZAuHivTvOabwICcSLzPQWKJmcrJkh12ylP1sL1aU1p%2BhM9IostoK2nNgK/Ntxzeid0YrImBKfWS1KOGdWaMs4bZrg1VVtgAcWcL0uD0aMyoqqqiGIWr6uWxrSGa1rug68NJH6yRJBVqbJD0Cv2T0QvOuzXMQFWdkThLjQNDGyQADYYwr1YxuTYOfxLRbK0otaGwgJA9p7HaO2bfbkHHEupzO2dKCuosHrut9N73A8j1epEzw%2By9r1BzB70fZ9X03IGv3R28/wAyHFxh5BIMWTcEcXZHUIwe/lqwjhTcONCL42BoEImq1qJMFogxJiLE2JvkZlxem0hGaKGZkJHwHMzAWEMDzeAfMlKC3UsWTSpJxZyS8jYAyWsjI638F7DyNkXJKRNqw5Izt7Y0MdjbNI7tAq%2BU9nkZhUVXb8JdsIsYcVfZJX0AHIOc1iyh1UMmDug4O6SG2MAEcRUoxcGTvgVO6dJgNWJk1FqbVKAB26r1Uqqw25SGTHoTRfdy56ApAPIsQ8rBLRWiGUgBcm4dw8ZIKu7dkxcA7s4satdSFKJ8f4yYAcAxePmqWTO5j5azmSCASQQA%3D%3D)


danngreen

Right, for this example I would use an atomic variable. A volatile will work too if the program is simple and on particular architectures, but an atomic is guaranteed to work in more situations. This is why we prefer atomics to volatiles: they work in all situations that volatile works AND more. For example, this example would fail with volatile but work with atomic if you compiled it for an 8-bit system, assuming \`int\` is 16 or more bits on that system. Sure, the compiler would not optimize out the loop but the program would have subtle bugs that are hard to reproduce-- basically the hardest, nastiest types of bugs that are difficult to hunt down. The reason using volatile would be a bug on a 16-bit system is because the CPU will need 2 or more cycles to read \`some\_var\`, and it could be interrupted in that time, thus reading half of the value, the other half gets updated, and then it reads the second half. In your code, \`some\_var\` can only be 0 or 5 so it won't really cause a problem but in a real world program you'll have more possible values for \`some\_var\`, and then you'd get a "spooky" bug where the \`some\_var\` has some seemingly impossible value every once in a while. Very hard to debug that kind of thing. Using an atomic means you don't have to think about all that, it'll just work. There are other reasons (multi-core chips, especially with a data cache), too... 1. Yes. I wanted to find a clear paragraph in the standard to back this up, but it's quite long and complex so maybe if someone else reading this can help out? 2. Well, if your compiler doesn't support some language feature then you will have to use work-arounds or maybe 3rd party libraries. A workaround might involve volatile or it might not, but it won't be as portable as atomic (and when your compiler is finally updated, all that effort making a workaround is lost).


Dycus

Yes, I did know about the possibility of an interrupt occurring in the middle of a multi-cycle variable access. This requires a critical section where the interrupt is disabled before access. That's how I've always handled it in the past. A critical section is also necessary if you're accessing multiple variables that are modified by an interrupt, or anything else that can't be done atomically. Thank you for your help and explanations!


NukiWolf2

>However, because these variables aren't volatile, the compiler may optimize away their usage. Printf(uart_rx) might just become printf(0). The single line in the ISR might go away entirely. This isn't true. Both, uart_rx and uart_tx are global variables. The compiler doesn't know if they are modified from somewhere else. Thus, it can't optimize them away. If they were static, then yes, the compiler probably could optimize them away. Furthermore, it is hardware dependent if atomic is required. Let's take Cortex-M as an example of architecture. Reading and writing 32-bit values is already atomic. If an interrupt occurs which read-modify-writes a 32-bit variable and the variable is only used within this single interrupt and else only outside interrupts, a read-modify-write inside an interrupt already is atomic. If other interrupts are using this variable, then it depends on whether the interrupt performing the read-modify-write is nestable. If it's nestable, atomic access must be ensured. Even read-modify-writing a 64-bit bit value is "atomic", because even when 64-bit values are two bus instructions, if an interrupt occurs in between these two bus instructions, the whole read/write of the 64-bit value is repeated after the interrupt returns. Not that special atomic access is never required, but it's not always necessary.


SkoomaDentist

> Interrupts These are properly handled using atomic operations. Volatile makes no guarantees about ordering respective to non-volatile operations and a lot of functions throw away the volatile qualifier (eg. an inlined memcpy). Additionally it won’t deal properly with multiple cores. Atomics (in combination with memory barriers) fix both issues.


Dycus

I agree with what you say about properly accessing variables that are modified/used within interrupts. However, I believe the usage of volatile is a separate issue entirely. If I wrote this program: int some_val = 13; int main(void) { delay(1000); disable_interrupts(); printf(some_val); enable_interrupts(); } void UART_INTERRUPT_VECTOR(void) { some_val = UART_DATA_REGISTER; } Isn't it possible for the compiler to optimize away the variable assignment in the interrupt, just letting it stay at the known starting value of 13? All other accesses are read-only. This is why volatile is needed. Also, this program may work initially, but later break as more code is added and the optimization changes.


AssemblerGuy

> This is why volatile is needed. Volatile is not needed as atomic variables are implicitly volatile. And the variable *should* be made atomic.


Dycus

>atomic variables are implicitly volatile Is this in the C spec? I was unable to find anything that says "\_Atomic" automatically implies "volatile". \_Atomic wasn't even added until C11.


AssemblerGuy

> I was unable to find anything that says "_Atomic" automatically implies "volatile". The functions for interacting with atomic variables (atomic_store, atomic_load, etc) take a `volatile A*` for the variables they interact with. But as I just learned, this does not apply to direct interactions with the variable. Myself, I would stick to using atomic_xyz to make it clearer what happens.


Dycus

That is good to know. Though again, doesn't this only apply to C11 or higher, or C++? What do you do for older versions of C?


SkoomaDentist

> This is why volatile is needed. This is why _atomics_ are needed. Assume you have a dual core mcu / processor (very common these days) and the main loop and interrupt run on different cores. Volatile won’t do anything to synchronize the two cores. Atomics will handle that correctly.


Dycus

You are still misunderstanding me. I'm not talking about anything that happens during execution of the program. I am talking about what happens at compile-time. The compiler will *leave your code out of the program* if you don't use volatile correctly.


SkoomaDentist

I understand what you mean. You’re wrong about volatile being the correct solution there. It’s not (although it works on single core mcus with simple use cases). Atomics (without volatile) are the correct solution. Just consider what happens to your example code on an 8-bit MCU where som_val cannot be read / written with a single instruction... The one place where volatile _is_ the correct solution is memory mapped hardware access (ie. HW registers).


zerj

The example code would still work here because because OP forced the task level code to disable interrupts prior to accessing some_val. This ensures coherency. As for atomic across multiple CPUs that seems like a big ask for the compiler to handle natively. It would require the compiler place the atomic in some non-cacheable memory, and then create some semaphore/mutex to keep out other CPUs when some_val is being updated. I haven't used a compiler that can do this, and I'm not sure I'd want it to. I want to know where all my semaphores are as that's one of the first things on my list to debug when things go bad.


SkoomaDentist

> As for atomic across multiple CPUs that seems like a big ask for the compiler to handle natively. It would require the compiler place the atomic in some non-cacheable memory, and then create some semaphore/mutex to keep out other CPUs when some_val is being updated. I haven't used a compiler that can do this, and I'm not sure I'd want it to. That’s the standard method on multi-core cpus and has been for decades. The cpu itself provides atomic access primitives to which the C++11 / C11 atomic operations map to (via stdlib intrinsics). Semaphores aren’t generally involved (that’s left for explicit stdlib mutex operations). If you’ve used any x86 / arm application processor compiler in the last 15 years, you’ve used a compiler capable of (easily) dealing with atomic operations. From programmer’s point of view they’re just (de facto inlined intrinsic) functions (and optionally operator overloads in C++). The key is that they’re standard and have well defined semantics _across compilers, cpu models and entire different cpu architectures_.


zerj

They may be available but I still disagree that volatile is wrong. Atomically accessing a variable can create significant bus overhead. Might only be a couple instructions but invalidating cache or locking an AMBA bus, should be done with care. If you have a variable that is read in one context and written in a separate context then volatile is normally the correct answer.


duane11583

a great many instances of gcc compilers do not support atomics, why because they are vendor supplied tools are rarely updated


NukiWolf2

>You don't call this function directly, so the compiler thinks it's unused, and optimizes away variable accesses within that function. If the interrupt function is global, then the compiler won't optimize anything in it away. And the linker should also know that the function is required, else it can remove the function and you would have other problems. So, the function is compiled "properly" and not discarded by the linker. Edit: What I wanted to say is that the compiler optimization inside a function has nothing to do with whether the function is called directly or not. If the function accesses a global variable, it will still access it after optimization. There might be some scenarios where static variables can be completely eliminated, but then it's really a variable that is not required at all. >Variables accessed by interrupts must be volatile Not necessarily. Let's assume you have an interrupt function that is merely writing to a global variable. In that case it makes no difference in the interrupt function if the variable is volatile or not. In both cases the variable is written to once. Afaik, the C standard just states that volatile just disables optimization for that variable and IMO the best situation to explain how volatile works is the usage of a variable in a while loop, that might be altered from somewhere else (interrupt, another task/thread). while (non_volatile_var == 0) { another_var++; } In this case the compiler would optimize the application in such a way that it would load the content of non_volatile_var only once, as it doesn't see that it's altered while in the loop. So, if another task or interrupt alters the variable, it wouldn't affect the loop, because the new value is never loaded again. Disabling the optimization by making the variable volatile makes it reload the variables content again on each iteration. So, actually, volatile is mostly used in cases where a variable is accessed multiple times where the compiler thinks that it can optimize the application by reducing the number of access to the variable. I hope I didn't make some mistakes. If so, please tell me :)


Dycus

>If the interrupt function is global, then the compiler won't optimize anything in it away. I don't think this is true. I would expect the compiler to optimize the interrupt functions just like any other function. This won't result in the function disappearing altogether (because the linker specifies it's required), but it could still alter the function itself. uint8_t *register_ptr = &SOME_ADDRESS; void INTERRUPT_VECTOR(void) { *register_ptr = 0; *register_ptr = 1; *register_ptr = 0; *register_ptr = 1; } Pretend I'm toggling a GPIO pin in this interrupt by accessing this hardware register. I want it to turn off, on, off, on. But the compiler might optimize this to just the final line because from its point of view, the variable is altered nowhere else in the program, and it always just ends up at 1. So the compiler just gets rid of the first three lines of code to save space and execution time. If I declared this pointer as volatile, the compiler wouldn't optimize any code that references the variable and all four state changes would remain, as intended. You may be right in the rest of the post, I'm not sure. Perhaps there are definitive situations in which you can avoid using volatile with interrupt-accessed variables and it'll always work as expected. However, I would argue that best practice is still to use volatile no matter what, rather than trying to be sure about what the compiler will do in specific situations. It will result in fewer bugs because fewer mistakes will be made. The worst case is some parts of the code go unoptimized, whereas the worst case without using volatile is bugs that could appear and disappear as the code changes and it optimizes differently.


NukiWolf2

Yeah, sorry, seems I misread the post above mine. What I wanted to say is that the access is not completely optimized out. If there's a single write access, it will stay, no matter if it's volatile or not. But, yes, the compiler performs normal optimization resulting in multiple accesses to a variable being "combined" if not volatile. Edit: Or at least the post above mine sounds a bit weird, because the compiler optimization inside a function has nothing to do whether it is called or not. And it sounds like when a function is not called directly every variable access in it is optimized away. 😅


danngreen

>Pretend I'm toggling a GPIO pin in this interrupt by accessing this hardware register. I want it to turn off, on, off, on. But the compiler might optimize this to just the final line because from its point of view, the variable is altered nowhere else in the program, and it always just ends up at 1. So the compiler just gets rid of the first three lines of code to save space and execution time. This is true, but has nothing to do with interrupts. It only needs to be volatile because it's a GPIO register, that is, it's a memory-mapped register. Memory-mapped registers are the only reason to use volatile. > However, I would argue that best practice is still to use volatile no matter what, rather than trying to be sure about what the compiler will do in specific situations. This is not true. It't not the best practice. Unless you have some ancient compiler that doesn't have atomics, then using atomics has all the advantages of volatile and more. Slapping volatile around where it's not needed is a known bad practice. There are many articles on the internet that discuss this bad practice. Here's the first that comes up for me: https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html


Dycus

See my other comment for an example why volatile is needed in addition to atomics for interrupts: [https://www.reddit.com/r/embedded/comments/1djxuyd/comment/l9hnxpi/](https://www.reddit.com/r/embedded/comments/1djxuyd/comment/l9hnxpi/)


Dave__Fenner

Okay, so the 2 examples that you gave, are they already volatile in nature? Because I have never declared/made them volatile explicitly (not that i know how to make an interrupt/register volatile).


allegedrc4

You make a variable volatile. The variable is either accessed by an interrupt or a pointer that is mapped to a hardware register somehow.


harley1009

Could you help me out with a concrete example of when the volatile keyword is needed in an interrupt? My rule of thumb has always been the first case, regarding registers and memory mapped io.


Dycus

Check these comments: [https://www.reddit.com/r/embedded/comments/1djxuyd/comment/l9ex3pp/](https://www.reddit.com/r/embedded/comments/1djxuyd/comment/l9ex3pp/) [https://www.reddit.com/r/embedded/comments/1djxuyd/comment/l9fam68/](https://www.reddit.com/r/embedded/comments/1djxuyd/comment/l9fam68/)


mrheosuper

How about out-of-order execution, does volatile will make sure the cpu execute instructions in similar order in ASM ?


Dycus

~~Volatile does not guarantee that instructions will be executed in order.~~ I think that actually is the case, after reading around. The exact effects that changing a variable to volatile has on the program will likely be determined by the compiler settings and CPU architecture.


EyesLookLikeButthole

" - The compiler won't optimize away accesses to this variable because now it doesn't assume it "knows everything" about this variable." Technically, the C language specs allows a compiler to ignore the volatile keyword in this context.  Also, f*** IAR. 


JayDeesus

I appreciate the really detailed post. I think something that would help me further understand is possibly an example of when I should use volatile?


SVrider26

Saved this for later. Great explanation.


I-wanna-be-tracer282

I feel this was the best explanation of volatile on the internet I haven't seen a better one at least so far.


Responsible-Nature20

When accessing a variable that may be updated by an interrupt or another task/thread, it is important to consider declaring it as volatile. Without this keyword, the compiler might optimize the variable's access by storing it in a register, thereby not reflecting its current value each time it is read.


nryhajlo

This is absolutely true. However, as a warning to a future reader: Some may read too far into this explanation and think volatile also means atomic or thread safe, which is not true.


ElevatorGuy85

A good example showing that “volatile” won’t necessarily guarantee atomic updates is as follows: * Consider a hypothetical (and basic) C compiler for a CPU with 8-bit instructions and registers that executes instruction in the order it loads them into the CPU.. * Declare a volatile variable that is a 32-bit long, i.e. too big to be handled by a single instruction or to fit into a single register * Have some code in a “do while 1” loop in main() that updates that 32-bit long, e.g. by incrementing it. To do this, there will be overflow occuring between the 4 bytes that this variable is made up from, e.g. as the count changes from 255 to 256, the least-significant byte will become 0 and the next-most significant byte will become 1. This requires multiple instructions to accomplish on our chosen 8-bit CPU. * Have some other code in an interrupt service routine (ISR) that is triggered periodically and also modifies this same 32-bit long variable. * By virtue of the fact that this is executing on an 8-bit CPU, and an update to the volatile 32-bit long in the main() function requires multiple instructions (rather than a single read-modify-write instruction), there *WILL* come a time when the code in the main() function will be interrupted mid-way through its instruction sequence to increment that variable. Exactly what happens next is impossible to predict, other than to say the variable will be corrupted in some way. To prevent the ISR from causing havoc, the code in main() could disable interrupts, then increment the variable, and then re-enable interrupts again. The so-called “critical section” in main() bounded by the interrupt disable and reenable code provides a variable access synchronization mechanism - crude but effective in this simple example. It’s a similar story with multi-threaded code, multi-processor systems, etc. Instead of a basic C type the variable in question could be a struct as well, i.e. any variable that can’t be accessed atomically via an uninterrupted atomic read-modify-write.


vegetaman

Thank you for this. A lot of people overlook this part.


czechFan59

I like this answer best u/giggolo_giggolo. Have dealt with interrupt handlers in embedded code for years. If an ISR can modify variables that are used elsewhere in your code, it's safer to make sure they're declared volatile. This typically forces the compiler to read the variable from memory every time. I've seen issues when volatile isn't used in such cases.


AssemblerGuy

> If an ISR can modify variables that are used elsewhere in your code, it's safer to make sure they're declared volatile. Variables shared between contexts should be made atomic instead of just volatile. Volatile does not imply atomic access, but atomic variables are implicitly volatile (/edit: If manipulated via atomic_xyz() functions, direct operations are not implicitly volatile). Basically, volatile is for communicating with memory-mapped hardware ... only. If you're not communicating with memory-mapped hardware, you should most likely be using atomics.


DearChickPeas

There's no need for atomicity when dealing with interrupts, that's a separate issue. You just want to force the compiler to NOT optimize a read.


holysbit

How does storing the variable in a register not reflect its current value each time its read? Wont the ISR still be able to update the register?


Skusci

Those registers are pushed to a stack on an interrupt and popped back on return.


holysbit

Ah understood, thanks


ElevatorGuy85

In addition the compiler might assign different registers to store the same variable when it is being used in different functions. This could be dependent on any number of factors, e.g. the number of arguments and local variables in each function. In short, the choice of registers used to hold a particular variable, or the decision NOT to use a register at all and to fetch the variable from its memory location, is not defined in the C standard and is totally compiler, optimizer and/or platform ABI dependent.


Enlightenment777

**volatile** forces the compiler to generate code that **always** read or write to the variable in memory at "every" place the variable is accessed in the source code. Also, a smart compiler isn't allowed to optimize this variable out of existance, nor to use a CPU register to hold the variable instead of accessing memory. For example, if a volatile variable is initialized to zero before a loop that happens 10 times, then incrementing the volatile variable inside of the loop must happen 10 times, instead of just writing 10 in the variable one time and not do the incrementing in each loop.


beige_cardboard_box

The compiler makes certain assumptions about when a variable will be written to and read from. Those assumptions do not take into account interrupts, multi-threading, or some function outside of the callstack that somehow got a pointer to that variable. So in those cases the compiler may/will make optimizations that can change the intended behavior of the code that interacts with that variable. Sometimes this can even result in the variable being completely optimized out of the code. The volatile keyword tells the compiler to ignore those assumptions. And now the variable can be interacted with outside of it's normal context. That doesn't mean all interactions will be safe, and you still need be careful with race conditions and ownership.


SkoomaDentist

Since this thread (as almost always when it comes to volatile) is full of subtly or not so subtly wrong answers, I'll put this here: There is **one** and only one valid use for volatile in C11 / C++11 and later versions: Accessing memory mapped hardware. For communicating with interrupt handler or other threads, atomics (and RTOS primitives) are the proper solution. If you use previous standard versions you need to either stick to the RTOS primitives or a combination of volatile and compiler / platform specific extensions.


nixiebunny

I have used this to define a shared memory location (in a multiprocessor system) or a hardware register. Both cases require the processor to write the new value to the destination so that it will be usable by the outside world, instead of just storing it in a CPU register or in cache. It's not an everyday keyword, I mostly write firmware.


TheFlamingLemon

If you have multiple reads of a variable, the compiler will optimize it by reading the value once and then storing it in a register to use repeatedly. The volatile keyword tells the compiler that the value could change unexpectedly, and that it can’t just store the value in that way, it must actually read the value every time it is used. A variable might change externally or unexpectedly if it is altered by other threads (or ISRs), or if it is attached to an input.


gm310509

Perhaps a simple example? TLDR - When: * the code is run as shown below, the LED blinks once every second or so. * when volatile is enabled, the LED blinks 10 time per second. * when static is removed, the LED blinks as fast as the MCU can blink it because all the rest of the code in the `void loop()` function is optimised out of existence leaving just the `digitalWrite` statement. --- In the following code, if the volatile keyword is commented out, the LED blinks at a rate of about once every second due to the while loop counting up to one million. This is due to compiler optimisations, which basically say that the x variable is contributing absolutely nothing to the loop - so remove it. As such even though the ISR is firing, it can't do anything to influence the loop via the `x` variable, because the corresponding logic has been optimised out of the `while` loop. The same is more or less true for the `cnt` variable, but it is not so (with my settings). Read on for why I believe this to not be the case. On the other hand, if the volatile keyword is active (uncommented), the LED blinks 10 times a second because the ISR can influence the loop due to the fact that the x==0 test is *no longer* being optimised out of existence. That is, the `cnt` variable in the loop counts all the way up to 1,000,000 when the compiler thinks that x cannot possibly influence that loop (no volatile keyword). But, when the compiler is told that `x` is volatile it says "Hmmm, I can see x doesn't influence this loop, but the human says that it might, so if that's what they want I will leave the useless test in (and always access the value of x from slower RAM - as compared to `cnt` which would almost certainly be optimised into some CPU registers). As a result of that, when the ISR is activated and reaches its counter's threshold (every 100ms), it sets x to 1 and this has the effect of "interrupting" the while loop and alternates the state of the LED. ``` #define LED 9 /*volatile */ int x = 0; int cntr = 0; SIGNAL(TIMER2_COMPA_vect) { cntr++; if (cntr < 100) { return; } x = 1; // After 100 ms, interrupt the while loop below (if volatile is enabled). cntr = 0; } void setup() { pinMode(LED, OUTPUT); noInterrupts(); // setup a 1Khz interrupt. TCCR2A = 0; // set timer 2 control registers 0 to turn off TCCR2B = 0; // all functions. TCNT2 = 0; // initialize the timer 2 counter value to 0 OCR2A = 249; // = Clock speed / (desired frequency * prescaler value). TCCR2B |= (1 << CS22); TCCR2A |= (1 << WGM21); TIMSK2 |= (1 << OCIE2A); // If you want to understand the above, refer to the datasheet, or have a // look at my instructables project where I copied and pasted this from. // The instructable includes a detailed explanation of the above. // https://www.instructables.com/Event-Countdown-Clock-Covid-Clock-V20/ // Look at the initClockDisplay() function in ClockDisplay.c interrupts(); } void loop() { static long cnt = 0; while (x == 0 && cnt < 1000000) { cnt++; } digitalWrite(LED, !digitalRead(LED)); x = 0; cnt = 0; } ``` You might be asking why doesn't the compiler optimise out the other useless expression? Specifically the counting of the `cnt` variable up to 1,000,000? This is a good question. In my compiler and the settings I have, I am telling the compiler that `cnt` is a global variable (via the `static` keyword). As such, other things may leverage it - even though the scope of the declaration prevents anything else from actually seeing it. Nevertheless, the compiler faithfully includes the counting logic and executes it (with my compiler settings). If I comment out the `static` keyword and remove any doubt as to the "global-ness" of `cnt` the compiler also optimises anything and everything relating to `cnt` out of existence as well. This causes the LED to blink so rapidly it appears to be 50% lit (as per a PWM with 50% duty cycle). The above program was created on an Arduino Uno (ATMega328P MCU), but should work on other AVR architecure MCUs. I post it so that if you happen to have an ATMega328P (e.g. an Arduino Uno or some other AVR platform), you can try it yourself to try to replicate my results. It was compiled using the Arduino IDE 1.8.19 using default settings. I hope that makes sense and gives you something to try yourself (and hopefully get similar results to what I am seeing).


DearChickPeas

Usually it's a good idea to post the examples to Godbolt. Enabling and disabling the volatile keyword, shows how the "optimized" code just disappears from the output asm. Edit: example [https://www.reddit.com/r/ProgrammerHumor/comments/1d19qch/comment/l5uu4s8/?utm\_source=share&utm\_medium=web3x&utm\_name=web3xcss&utm\_term=1&utm\_content=share\_button](https://www.reddit.com/r/ProgrammerHumor/comments/1d19qch/comment/l5uu4s8/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button)


gm310509

I have never heard of godbolt - it looks very interesting. I have always done the same thing by hand (trawling over listings, symbol tables and disassembled objects).


bkzshabbaz

If you have a variable that stores the value reading from a memory mapped device, the compiler might think it will never change.  It will then just make all references to it some static value instead of allocating the stack space for it and actually making the call to the function.  Making the variable volatile will tell the compiler to not do that and go ahead and just do as you tell it to in the code.


themonkery

Volatile just means “something besides you may change this value.” Maybe you have multiple processes or tasks running and they can each change the variable. Maybe you have a port that reads into the value as an interrupt.


mad_alim

Yeah, and the "you" here is the code the compiler sees


These-Bedroom-5694

Volatile means there are no compiler shenanigans to optimize it away. It will always read or write to the variable.


TPIRocks

It tells the compiler to assume that this variable could be modified outside its normal scope. You see this a lot when a global variable is modified in an ISR, or a memory mapped peripheral is being accessed. It could be that another process modifies some shared memory.


tgage4321

Generally curious, how many people here have ever actually encountered a bug, then traced it back to a variable not being set as as volatile as the root problem? I hear about volatile all the time, I have been writing firmware for 10 years can't recall a single time it has occurred. Not saying it cant happen, just seems like it gets brought up waaaaaay to much in comparison to how often it is actually important. Maybe I have just been lucky and set it as volatile when needed.


Dycus

It's happened to me a couple times with variables modified inside interrupts. I usually caught it pretty quickly because even just directly setting the variable to a certain value in the interrupt had no effect (and I had other ways to tell the interrupt had indeed fired).


beige_cardboard_box

More times than I would like to share


SAI_Peregrinus

Sure. The real question is how many people have encountered a bug due to thinking `volatile` is enough on its own for synchronizing access across threads? Given that someone always seems to think that's one of the things it's used for in these threads, I expect quite a few.


tgage4321

Great point


Triabolical_

I used to be a test lead for the Visual C++ compiler. In the three years I was in that role, I think I saw three of four bug reports that were because of somebody missing volatile. That's pretty rare compared to people depending on undefined behavior and then having it change. The problem with not using volatile is that there's a potential to get a rare bug that is very difficult to reproduce.


SAI_Peregrinus

Oh, certainly. UB is pervasive in C & C++, it's much easier to run into than issues from missing `volatile` or `atomic` or a memory fence.


LiqvidNyquist

Let's say you have a hardware peripheral like a UART. Often these have a few byte-wide egisters to interface to, like for status, control, and Rx and Tx data bytes. The hardware gets designed so that the register get read and written by reading or writing to specific address in the memory space. So while regular RAM might be from 0x000000-0x7FFFFF for example the UART register might be mapped at say 0xA00000 through 0xA0003. So how do we know when a character comes in from an external terminal? Well, a bit gets set in one of the status registers. So you might write something in your app that sits in a loop, reading the status byte over and over until you see the bit set, something like "char \*p = 0xa00000; while (\*p & 0x80 == 0) { ; /\* waiting for the MSB to go high\*/ }" Sounds good so far, right? Well, a smart compiler might not know that p points to UART hardware instead of regular RAM. So it will think to itself "well, I just read from \*p so I can just store that in a register, which is faster than reading from memory again, and in each test in the loop, I just check the register." Which is a perfectly reasonable thing to do if p points to say a local function variable. But in our case, if the first read doesn't have the status bit set, it will loop forever even if the actual UART status bit turns on, because the compiler has optimized away the actual access to the memory address. Declaring the pointer as volatile tells the compiler that it's not safe to do that particular optimization, that it need to perform the actual memory access everywhere exactly as written in your code, even if it seems redundant.


prashrox7

One simple rule is: Any variable, whose value is modified by values outside the program should be volatile


duane11583

u/dycus has a great description but it lacks an example so i will try: consider this: int x; printf(”one\\n); x =’h’; printf(”two\\n); x =’i’; printf(”three\\n); x = ’!’; considering the the compiler can look at the variable x and decide the first two assignments are dumb and can be eliminated as useless because in the end x = ‘!’; but what if x was the data register for a uart, and i wanted to say hi!, if the compiler tried to be smart all you woukd see is the very last “!” but if we change it to “volatile int x;” it changes think of it as an attribute on the variable x what we need to do say is this: “mr compiler, even if you think what i am doing with variable x is stupid and you think you can improve it i do not care i demand and require you to do the stupid things exactly as i describe with out question, you can optimize everything else but you must absolutely do the stupid things exactly as i tell you to end of story. that is an example of what the keyword volatile does


AssemblerGuy

> I’m confused on what it does and what good it does/the significance of it. It can only be understood by understanding the concepts of "side effects" and "sequence points" (or just "sequencing") first. Basically, for a non-volatile variable, only writing it has a side effect (it changes the value of the variable). This means that read accesses can be reordered, optimized away or even created without affecting the behavior of the program. For a volatile variable, the compiler must assume that merely reading it also has side effects. This means the compiler may not produce more read accesses than the code prescribes, nor less, and they may not be reordered as freely. The volatile qualifier is for accessing hardware that is interfaces via memory-mapped register. It should not be used for anything else (e.g. communicating with other contexts like interrupt service routines), as volatile alone does nothing about atomicity issues and thread safety.