Keyser Soze wrote:
We do a lot of embedded C code so we test compiliers on how they handle
volatile data types. Some of the test code we use is so abreviated as to
have no real functionality other than to test the code generator.
One compiler we tested claims to conform with ISO C but has a somewhat
nonconformist way of working with volatile data types.
Specifically:
int volatile a;
void test1(void)
{
a = a + 0;
}
void test2(void)
{
a += 0;
}
The code produced by function test1 was correct.
The variable 'a' was read then written.
The code produced by function test2 was incorrect.
The variable 'a' was read but not written.
When we suggested that the code for test2 did not conform we were told
the
expression has only one sequence point and that the generated code was
correct.
Using compound assignment operators when dealing with
volatile-qualified objects that are "sensitive" to the difference
(usually hardware registers) is a classic no-no. Here's my best
explanation:
C99: 5.1.2.3 Program execution
[#6] The least requirements on a conforming implementation are:
-- At sequence points, volatile objects are stable in the
sense that previous accesses are complete and
subsequent accesses have not yet occurred.
GCC 4.02 Manual:
4 C Implementation-defined behavior
4.10 Qualifiers - When is a Volatile Object Accessed?
[...]
The minimum either standard specifies is that at a
sequence point all previous accesses to volatile objects
have stabilized and no subsequent accesses have occurred.
Thus an implementation is free to reorder and combine
volatile accesses which occur between sequence points,
but cannot do so for accesses across a sequence point.
6.7.3 Type qualifiers
[#6] An object that has volatile-qualified type may be
modified in ways unknown to the implementation or have other
unknown side effects. Therefore any expression referring to
such an object shall be evaluated strictly according to the
rules of the abstract machine [...]
6.5.16.2 Compound assignment
[#3] A compound assignment of the form E1 op= E2 differs
from the simple assignment expression E1 = E1 op (E2) only
in that the lvalue E1 is evaluated only once.
"E1" is evaluated "only once", and implementations are (at least
according to the GCC group's interpretation) "free to reorder and
combine volatile accesses which occur between sequence points". I
believe the compiler's behavior in this case is conforming.
At least that's my interpretation. Dissent or confirmation is welcome.
Personally speaking, I have never used compound assignment to
volatile-qualified types in any device drivers I've ever written.