What does volatile actually do?

Can someone explain what volatile does? Ideally with examples, like explaining what some code snippet would do without and with or so.

Your accepted answer is incorrect and misleading and you should delete it. Please refer to the official volatile documentation.

4 Likes

I re-marked the solution to point to the official documentation.

That was also my original starting point but I struggled to umderstand what it means, after reading the stackoverflow post I thought I did and I honestly dont see the difference

It says that I should use volatile in cases like mmio, but not why

Consider you have a device connected to your CPU via MMIO that acts as a simple state machine. Two back-to-back writes of 0xDEADBEEF cause the device to self-destruct, and any other writes reset the device. In Zig, you may have some code to initiate a self-destruct that looks like:

fn selfDestruct(mmio: *u32) void {
    mmio.* = 0xDEADBEEF;
    mmio.* = 0xDEADBEEF;
}

Does this work? Well, the answer is… maybe, but probably not. Any optimized compiler would see the second write as redundant and remove it. The volatile keyword tells the compiler that reads/writes to a particular address have side effects (advancing the internal state machine within our device) and therefore must not be ignored, even if it seems more optimal. The correct code would then be:

fn selfDestruct(mmio: *volatile u32) void {
    mmio.* = 0xDEADBEEF;
    mmio.* = 0xDEADBEEF;
}
6 Likes

Thank you that was a genuinely really comprehensive explenation, I appreciate it

1 Like