Say, I have this code:
int f() {
volatile int c;
c=34;
return abc();
}
The volatile int c is never read. But it is marked as volatile, can the compiler eliminate it altogether? My testing in Visual C++ 2010 shows contradictory results. In VC++, if I enable optimization (maximizing speed) the above function contains a local variable called c (by looking at the generated assembly listing). But, instead of using assignment operator, I also tried to initialize the variable by a compiler intrinsic function like memset() (and enable using compiler intrinsic functions), the variable is eliminated.
int f() {
volatile int c;
memset((void*)&c,34, 1);
return abc();
}
So according to the C++ standard, can compiler eliminate the volatile int c? I'm thinking probably there is some inconsistent behaviour in VC++ related to how intrinsic functions optimize volatile variable.
So according to the C++ standard, can compiler eliminates the volatile int c?
No. volatile
-qualified objects are used for reading from or writing to the hardware, and the side-effects of assigning a volatile
object are observable.
Therefore, in compliance with the constraints on optimizations placed by the so-called "as-if" rule, conforming implementations are not allowed to optimize away c
. The "as-if" rule is formally introduced in Paragraph 1.9/1 of the C++11 Standard:
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract
machine. This International Standard places no requirement on the structure of conforming implementations.
In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming
implementations are required to emulate (only) the observable behavior of the abstract machine as explained
below
And the concept of "observable behavior" is defined in paragraph 1.9/8:
The least requirements on a conforming implementation are:
— Access to volatile objects are evaluated strictly according to the rules of the abstract machine.
— At program termination, all data written into files shall be identical to one of the possible results that
execution of the program according to the abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take place in such a fashion that prompting
output is actually delivered before a program waits for input. What constitutes an interactive device
is implementation-defined.
These collectively are referred to as the observable behavior of the program. [...]
Since access to volatile
objects must be evaluated strictly according to the rules of the abstract machine, compilers are not allowed to optimize away c
and the corresponding assignment operation.
memset((void*)&c,34, 1);
has undefined behaviour (§7.1.6.1/6). The compiler is therefore allowed to produce any result.
If an attempt is made to refer to an object defined with a volatile-qualified type through the use of a glvalue with a non-volatile-qualified type, the program behavior is undefined.
Please, do not use casts like that, much less C-style casts. When one does not know what the correct C++ cast is for a certain situation, it is likely a situation where one should not be casting anything.