Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > return x = 0; // under C99 for volatile x

Reply
Thread Tools

return x = 0; // under C99 for volatile x

 
 
Tim Rentsch
Guest
Posts: n/a
 
      01-13-2010
Francois Grieu <(E-Mail Removed)> writes:

> Hi, consider:
>
> volatile unsigned char x;
> unsigned char foo(void) { return x = 0; }
>
> Assuming conformant C99, when foo is executed, is the value returned
> a) allways 0
> b) what was read from x after x has been written with 0
> c) unspecified.


This is a murky area as to what the Standard actually mandates.
Furthermore it is complicated by the implementation-definedness
of "what constitutes an access to a volatile-qualified" object;
writing 'return x = 0;' is likely to lead to different results
with different compilers. Better to spell it out explicitly,
that is, write either

return x = 0, x;

or

unsigned char t;
return x = t = 0, t;

(or something similar to one of the above depending on personal
stylistic preferences).
 
Reply With Quote
 
 
 
 
Tim Rentsch
Guest
Posts: n/a
 
      01-13-2010
Seebs <(E-Mail Removed)> writes:

> On 2009-12-17, Phil Carmody <(E-Mail Removed)> wrote:
>> Seebs <(E-Mail Removed)> writes:

> (in re
>>>> volatile int buffer_ready;
>>>> char buffer[BUF_SIZE];
>>>> void buffer_init() {
>>>> int i;
>>>> for (i=0; i<BUF_SIZE; i++)
>>>> buffer[i] = 0;
>>>> buffer_ready = 1;
>>>> }

>
>>>> "The for-loop does not access any volatile locations, nor does it
>>>> perform any side-effecting operations. Therefore, the compiler is free
>>>> to move the loop below the store to buffer_ready, defeating the
>>>> developer's intent."

>
>>> Hmmm. Interesting. Well, first off, I'd point out that unless there's more
>>> to it, buffer is obviously all zeroes already, making the question moot.

>
>> That's not obvious at all. We don't have any idea what else happens
>> before the call to buffer_init().

>
> As I said, "unless there's more to it". If there's other code affecting
> these, it's hard to guess. Without other code, though, it's moot.
>
>> What is obvious is that the first quoted sentence is just plain
>> false, and therefore the second sentence's 'therefore' does not
>> necessarily follow, and indeed cannot follow.

>
> Agreed. It is pretty obvious that the loop performs assignment, which is
> an operation with side effects.
>
> That said:
>
> In general, a compiler is permitted to reorder side effects on non-volatiles
> as long as a strictly conforming program can't tell the difference. So,
> if you ran this on a threaded system, it's not obvious to me that the compiler
> couldn't reorder the side effects on the buffer to later in the function,


Again this is a murky area because of the implementation-definedness
of what constitutes a volatile-qualified access. However, for any
reasonably sensible such definition, the side effects on the buffer
would have to be done before the volatile access, because access to
volatile-qualified objects must be done strictly according to the
abstract semantics, which includes completing all side effects of
all previous expressions.

> because a strictly conforming program has no way to peek at the buffer
> and the volatile flag until the function returns... [snip rest]


Any program that uses 'volatile' is affected both by unknown
side effects and the implementation-defined aspects as to what
constitutes a volatile-qualified access; such a program therefore
can never be strictly conforming.
 
Reply With Quote
 
 
 
 
lawrence.jones@siemens.com
Guest
Posts: n/a
 
      01-13-2010
Kaz Kylheku <(E-Mail Removed)> wrote:
>
> An assignment expression has the value of the left operand, after
> the assignment (and not: the value that is stored in the operand
> /by/ the assignment).
>
> Access to a volatile object is a side effect.
>
> So, after zero is stored in it, the object x must be accessed again to
> retrieve the stored value.


That's a common misconception, it was not the committee's intent. The
committee intended that "after" could be taken as "immediately after",
in which case the compiler can infer the value without having to refetch
it (although it's certainly allowed to refetch if it wants).
--
Larry Jones

The living dead don't NEED to solve word problems. -- Calvin
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      01-13-2010
http://www.velocityreviews.com/forums/(E-Mail Removed) writes:
> Kaz Kylheku <(E-Mail Removed)> wrote:
>> An assignment expression has the value of the left operand, after
>> the assignment (and not: the value that is stored in the operand
>> /by/ the assignment).
>>
>> Access to a volatile object is a side effect.
>>
>> So, after zero is stored in it, the object x must be accessed again to
>> retrieve the stored value.

>
> That's a common misconception, it was not the committee's intent. The
> committee intended that "after" could be taken as "immediately after",
> in which case the compiler can infer the value without having to refetch
> it (although it's certainly allowed to refetch if it wants).


What if the value of the RHS expression of the assignment is never
actually stored in the object, or at least can never be retrieved
from the object?

For example:

volatile int x;

x = 42;

Isn't it possible for an implementation to define "volatile" in such a
way that assigning the value 42 to x has some particular
implementation-defined effect, but that affect doesn't include storing
the value 42 in x?

Must this:
int foo(void) { return x = 42; }
have the same effect as this:
int foo(void) { x = 42; return x; }
?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      01-13-2010
On 2010-01-13, (E-Mail Removed) <(E-Mail Removed)> wrote:
> Kaz Kylheku <(E-Mail Removed)> wrote:
>>
>> An assignment expression has the value of the left operand, after
>> the assignment (and not: the value that is stored in the operand
>> /by/ the assignment).
>>
>> Access to a volatile object is a side effect.
>>
>> So, after zero is stored in it, the object x must be accessed again to
>> retrieve the stored value.

>
> That's a common misconception, it was not the committee's intent.


There is no misconception. The text clearly says that ``An assignment
expression has the value of the left operand after the assignment, but is not
an lvalue.''

> The
> committee intended that "after" could be taken as "immediately after",


This is a mostly meaningless distinction. Either two events A and B are
simultaneous or either A is after B or vice versa.

``Immediately after'' is some subjective judgment which usually means that one
event follows the other such that there are not intervening events (at least no
intervening events from among class of events that are relevant to the
situation: A happens after B such that nothing relevant happens in between,
hence A happens immediately after B.

But there does not have to be an intervening event in order for the value of
the object to be different from what was stored.

For instance, if the lvalue denotes a memory-mapped register, the register
could have the semantics of control on write, and status on read. At no time
does the register ever play back the control word.

Thus ``value of the left operand'' is always, unabiguously, the status word,
regardless of how soon after the write the value is sampled.

> in which case the compiler can infer the value without having to refetch


Inferring the value without refetching it means that the value is not in fact
that of the left operand after the assignment.

Of course, this is is an optimization which is permitted in the absence of
volatile.

For a volatile object, this optimization is not permitted by the text
which requires that the expression has the value of the left operand.

> it (although it's certainly allowed to refetch if it wants).


So now you are saying that the committee intent is to actually de-clarify the
clear text. What may be implemented is either the straightforward
interpretation, or another one.

This is puzzling. See, usually statements of intent do the opposite: there is a
text with two or more possible meanings and the clarification of intent makes
it clear which one it is. So here there is a text with one meaning, and the
intent is to have two meanings? Hmm.

Do you have a copy of some ISO correspondence related to this?
 
Reply With Quote
 
lawrence.jones@siemens.com
Guest
Posts: n/a
 
      01-14-2010
Keith Thompson <(E-Mail Removed)> wrote:
> (E-Mail Removed) writes:
> >
> > That's a common misconception, it was not the committee's intent. The
> > committee intended that "after" could be taken as "immediately after",
> > in which case the compiler can infer the value without having to refetch
> > it (although it's certainly allowed to refetch if it wants).

>
> What if the value of the RHS expression of the assignment is never
> actually stored in the object, or at least can never be retrieved
> from the object?


The abstract machine doesn't admit to such possibilities. A volatile
object is still an object with normal object semantics (e.g., it retains
its last stored value), it's just that its value can be stored in ways
unknown to the implementation and accessing it may have additional side
effects. Something like a memory mapped i/o port where the value read
has nothing whatsoever to do with the value previously stored still fits
that model if you assume that the abstract object's value is modified by
an unknown external agent right after each store, but an implementation
is allowed to decide that the value of an assignment to the object is
the value before that external agent gets a chance to modify it.

> Must this:
> int foo(void) { return x = 42; }
> have the same effect as this:
> int foo(void) { x = 42; return x; }


No, it's also permitted to have the same effect as:
int foo(foid) { x = 42; return 42; }

The only reason for the peculiar wording was to handle the cases where
the value is changed by the assignment in ways that aren't obvious from
the overt type of the left hand side (e.g., the value is truncated when
assigned to a small bit-field).
--
Larry Jones

Kicking dust is the only part of this game we really like. -- Calvin
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      01-14-2010
Kaz Kylheku <(E-Mail Removed)> writes:

> On 2010-01-13, (E-Mail Removed) <(E-Mail Removed)> wrote:
>> Kaz Kylheku <(E-Mail Removed)> wrote:
>>>
>>> An assignment expression has the value of the left operand, after
>>> the assignment (and not: the value that is stored in the operand
>>> /by/ the assignment).
>>>
>>> Access to a volatile object is a side effect.
>>>
>>> So, after zero is stored in it, the object x must be accessed again to
>>> retrieve the stored value.

>>
>> That's a common misconception, it was not the committee's intent.

>
> There is no misconception. The text clearly says that ``An assignment
> expression has the value of the left operand after the assignment, but is not
> an lvalue.''
>
>> The
>> committee intended that "after" could be taken as "immediately after",

>
> This is a mostly meaningless distinction. Either two events A and B are
> simultaneous or either A is after B or vice versa.
>
> ``Immediately after'' is some subjective judgment which usually means that one
> event follows the other such that there are not intervening events (at least no
> intervening events from among class of events that are relevant to the
> situation: A happens after B such that nothing relevant happens in between,
> hence A happens immediately after B.
>
> But there does not have to be an intervening event in order for the value of
> the object to be different from what was stored.
>
> For instance, if the lvalue denotes a memory-mapped register, the register
> could have the semantics of control on write, and status on read. At no time
> does the register ever play back the control word.
>
> Thus ``value of the left operand'' is always, unabiguously, the status word,
> regardless of how soon after the write the value is sampled.
>
>> in which case the compiler can infer the value without having to refetch

>
> Inferring the value without refetching it means that the value is not in fact
> that of the left operand after the assignment.
>
> Of course, this is is an optimization which is permitted in the absence of
> volatile.
>
> For a volatile object, this optimization is not permitted by the text
> which requires that the expression has the value of the left operand.
>
>> it (although it's certainly allowed to refetch if it wants).

>
> So now you are saying that the committee intent is to actually de-clarify the
> clear text. What may be implemented is either the straightforward
> interpretation, or another one.
>
> This is puzzling. See, usually statements of intent do the opposite: there is a
> text with two or more possible meanings and the clarification of intent makes
> it clear which one it is. So here there is a text with one meaning, and the
> intent is to have two meanings? Hmm.


First let me say that I share some of these reactions to the
existing wording. The "plain meaning" seems to require a write
and a subsequent read for a volatile-qualified access. Worse,
the description written is just vague enough so that the point is
debatable -- always a bad sign.

Having said that, the Standard does contain a clear out that
allows either interpretation (reading after assigning, or not
reading after assigning) to be chosen by an implementation,
namely, the proviso that what constitutes a volatile-qualified
access is implementation-defined. For better or worse, that
clause provides enough wiggle room so that an implementation can
choose either interpretation -- and, as far as I can tell, not
even necessarily consistently from one assignment to the next.
Rather a sad state of affairs, but given how things are it seems
best to accept the potential ambiguity and just avoid using the
result of a volatile-qualified assignment in cases where which of
the two possibilities is chosen might make a difference.
 
Reply With Quote
 
Phil Carmody
Guest
Posts: n/a
 
      01-14-2010
(E-Mail Removed) writes:
> Kaz Kylheku <(E-Mail Removed)> wrote:
>>
>> An assignment expression has the value of the left operand, after
>> the assignment (and not: the value that is stored in the operand
>> /by/ the assignment).
>>
>> Access to a volatile object is a side effect.
>>
>> So, after zero is stored in it, the object x must be accessed again to
>> retrieve the stored value.

>
> That's a common misconception, it was not the committee's intent.


It's not a misconception, it's an interpretation of what the committee
wrote. All other interpretations require horrible hand-waving, flapping
and pleading with the audience.

If it was not the committee's intent, then the committee desperately
needs to reword the sentence.

> The
> committee intended that "after" could be taken as "immediately after",
> in which case the compiler can infer the value [...]


I don't see 'inferring' as being compatible with 'volatile'. Volatile
means _no_ short cuts, even if two things are immediately after each
other:

extern volatile int flag;
if(flag^flag) unbrundle();

Are the two accesses to flag not immediately after each other?
Yet no-one in their right might would infer that the two accesses
could be reduced to one.

So, the way you've expressed it here, I think the committee needs
to change its intentions, rather than the wording of the paragraph.

Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      01-14-2010
On 2010-01-14, (E-Mail Removed) <(E-Mail Removed)> wrote:
> Keith Thompson <(E-Mail Removed)> wrote:
>> (E-Mail Removed) writes:
>> >
>> > That's a common misconception, it was not the committee's intent. The
>> > committee intended that "after" could be taken as "immediately after",
>> > in which case the compiler can infer the value without having to refetch
>> > it (although it's certainly allowed to refetch if it wants).

>>
>> What if the value of the RHS expression of the assignment is never
>> actually stored in the object, or at least can never be retrieved
>> from the object?

>
> The abstract machine doesn't admit to such possibilities. A volatile
> object is still an object with normal object semantics (e.g., it retains


No it is not. This is completely a wrong path to take regarding
the meaning of an assignment expression; it does not rest on the
semantics of volatile, but on the semantics of ``assignment expression''.

> its last stored value), it's just that its value can be stored in ways


The volatile qualifier expresses precisely the opposite idea: that the object
does not have normal object semantics: that it cannot be relied upon to retain
its last stored value.

Caching optimizations rely on objects retaining their last stored value,
so that the cached copies can be trusted to be coherent with the original.

volatile defeats such optimizations for objects which are known, or suspected
of violating this coherency requirement.

> The only reason for the peculiar wording was to handle the cases where
> the value is changed by the assignment in ways that aren't obvious from
> the overt type of the left hand side (e.g., the value is truncated when
> assigned to a small bit-field).


There are other ways to express such an intent
without actually saying that the value of the expression /is/ that of
the left operand.

Now let's think about this. Suppose that the lvalue foo.three is
an unsigned bit-field, three bits wide, and suppose that it's
a normal object which retains its last stored value.

If we perform this expression:

return foo.three = 42;

the value 42 is reduced modulo 8 into the range 0-7, and that resulting value
is also returned.

Why does assignment return this reduced value?

Argument: it's could be because the value is understood as going into the
object, and then emerging again to form the result.

If the value does not go into the object, there is no reason to reduce
it to three bits; the assignment expression might as well yield 42.

I.e. the right hand side is shunted into the object, where it must be reduced,
/and/ it is also returned.

For that matter, the resulting value can have the original type, too.

Someone designing a language in which the assignment /forks/ the value into two
destinations might not design it this way. The resulting value would be the
original value of the right hand side, of the original type. That's a much
more sensible design: why introduce a potentially dangerous conversion where
one isn't needed?

For instance, we could have a C dialect in which the following initializes
the two real values to 3.14:

double1 = double2 = integer = 3.14;

The 3.14 is truncated when it is shunted into the integer, but the
result of (integer = 3.14) is of type double, so the original 3.14 (or best
approximation of that constant in the double type) propagates to real2 and
real1. Basically, the initialization is fully paralellizeable.

If you want an alternate rationale for the strange wording which
supports your case, how about this: it is necessary because without it,
expressions like the following would be undefined behavior:

node = node->next = NULL;

The NULL could race ahead and get stored into node, turning node->next
into a null dereference. The wording ``value of the left operand after the
assignment'' introduces a data flow constraint which allows expressions like
the above to be harmless and even useful.
 
Reply With Quote
 
Kaz Kylheku
Guest
Posts: n/a
 
      01-14-2010
On 2010-01-14, Tim Rentsch <(E-Mail Removed)> wrote:
> Having said that, the Standard does contain a clear out that
> allows either interpretation (reading after assigning, or not
> reading after assigning) to be chosen by an implementation,
> namely, the proviso that what constitutes a volatile-qualified
> access is implementation-defined.


The implementation-defined constitution of a volatile access in no way permits
an actual access to be omitted when an abstract access is called for to a
volatile object.

The ultimate conclusion if this interpretation is that any and all volatile
access can be optimized in exactly the same way as regular accesses,
which is preposterous. An implementation cannot simply say that ``Sometimes,
just to thumb our noses at the programmer, a volatile access is constituted of
nothing: our compiler infers the value without consulting the object.''

If this were the case, then the standard-blessed volatile sig_atomic_t trick in
a singal handler wouldn't work, and volatile would not ensure the proper
behavior of modified local variables between a setjmp and longjmp.

Cleary, a failure to access the object at all cannot possibly constitute any
kind of access to that object! That is just nonsense and anyone who implements
along those lines will not produce a viable tool, even if it may be regarded as
conforming. (The /bin/true program on Unix can be regarded as a conforming
impelmentation of C90, too, due to poor wording in the standard).

The authors of the paper _Volatiles Are Miscompiled, and What to Do about It_
looked hard, and up the most plausible reason for the implementation-defined
constitution of a volatile access. They provide the following reference to a
Usenet posting by Doug Gwyn, who was on the standardization committee for C90:

Douglas Gwyn. NEVERMIND! (was: Re: A question on volatile
accesses). USENET post to comp.std.c, November 1990.
http://groups.google.com/group/comp....09e4162620f2cd.

Chasing that reference:

``However, although it was proposed that conforming implementations be
required to implement the minimum possible access "width" for
volatile-qualified data, and that is the intent of requiring an
implementation definition for it, it was not practical to insist on it
in every implementation; thus, some latitude was allowed implementors
in that regard.''

See there is the question of width. If accessing an object has side effects,
there is the issue that a C lvalue doesn't necessarily correspond to the
addressable range that is tied to the same effect. Accessing an unsigned char
x[0] may produce the a side effect related also to adjacent x[1].
So in fact, the access to x[0] constitutes not only an access to x[0]
but an access to x[1], and possibly elsewhere.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
volatile in C99 George C Programming 3 12-01-2008 11:20 PM
I don't find the keyword "volatile" in C99.............. lostlander C Programming 3 09-19-2007 11:35 AM
Difference between "library parts" of C99 and "language parts" of C99 albert.neu@gmail.com C Programming 3 03-31-2007 08:14 PM
C99 struct initialization (C99/gcc) jilerner@yahoo.com C Programming 3 02-20-2006 04:41 AM
Use of the Volatile keyword for a pointer to a volatile memory block ben C Programming 5 01-11-2005 05:38 PM



Advertisments