In this example, does correctness require global_value to be declared volatile?
int global_value = 0;
void foo () {
++ global_value;
}
void bar () {
some_function (++global_value);
foo ();
some_function (++global_value);
}
My understanding is that volatile is "intended" for pointers to mapped memory and variables which can be modified by signals (and emphatically not for thread-safety) but it’s easy to imagine that bar might compile to something like this:
push EAX
mov EAX, global_value
inc EAX
push EAX
call some_function
call foo
inc EAX
push EAX
call some_function
mov global_value, EAX
pop EAX
This is clearly not correct, but even without volatile I believe it is valid according to the C abstract machine. Am I wrong or is it valid?
If so, it seems to me that volatile is routinely overlooked. This would be nothing new!
Extended Example
void baz (int* i) {
some_function (++*i);
foo ();
some_function (++*i);
}
int main () {
baz (&global_value);
}
Even if bar is guaranteed to compile into a correct dont-cache-global_value implementation, will baz be similarly correct, or is it allowed to cache the non-volatile value of *i?
No, the
volatilekeyword is not necessary here. Sinceglobal_valueis visible outside the functionbar, the compiler must not assume that it remains the same if another function is called.[Update 2011-07-28] I found a nice citation that proves it all. It’s in ISO C99, 5.1.2.3p2, which I am too lazy to copy here in its entirety. It says:
Sequence points include:
There you have your proof.