Re: Another ANSI C question about 'volatile'

From: Tim Rentsch (txr_at_alumnus.caltech.edu)
Date: 08/16/04


Date: 16 Aug 2004 10:33:06 -0700

Jack Klein <jackklein@spamcop.net> writes:

> On 15 Aug 2004 20:40:44 -0700, Tim Rentsch <txr@alumnus.caltech.edu>
> > [stuff omitted]
> >
> > I'd thought of the 'y = *(volatile int *)&x;' before, but I concluded
> > it had the same problem as 'y = (volatile int)x;' -- because the
> > subexpression '(volatile int *)&x' isn't an lvalue (by which I mean,
> > can't be on the left hand side of an assignment operator), the
> > 'volatile' type qualifier is discarded. Or do I misunderstand
> > what the standard means by 'lvalue'?
>
> Yes, you did understand what is meant by 'lvalue' in this case.
>
> The cast is on the address of x. The result of the cast is indeed an
> lvalue of type 'pointer to volatile int'. The pointer itself is not
> volatile, which would indeed be meaningless. But the type pointed to
> by the pointer is not an lvalue, and that is what the 'volatile' in
> the cast applies to.

Here is my problem. The result of the cast is not an "lvalue" as I am
used to the term. Reason being, writing an assignment statement that
starts

    (volatile int *) &x = ...

isn't legal. Of course it is legal if there is a '*' in front of the
cast, but that's a different expression. My best understanding now
is that the expression '(volatile int *) &x' is an 'lvalue' as the
term is used (and defined) within the C standard. If this expression
is an lvalue, then the 'volatile' qualifier is retained, and
everything works fine. And -- as I just found out -- the Rationale
has a supporting statement along these lines:

    If it is necessary to access a non-volatile object using
    volatile semantics, the technique is to cast the address
    of the object to the appropriate pointer-to-qualified type,
    then dereference the pointer.

So there you have it.

> > Incidentally, what about this idea:
> >
> > int * volatile xp = &x, y = *xp;
>
> No, this does not do the same thing at all. Type qualifiers 'const'
> and 'volatile' (and probably 'restrict', but I haven't checked) modify
> what appears to their left. In this case you are defining 'xp' as a
> volatile pointer to a non-volatile int.
>
> Technically that should mean that the compiler must read the value of
> the pointer xp every time you dereference it, rather than relying on a
> cached value in a register or whatever. Common sense would indicate
> that a compiler, needing to reread xp each time, would then
> dereference it to access memory each time, but the standard does not
> require this behavior.
>
> You are unlikely to find one, but since the integer pointed to by xp
> is not volatile, a compiler would be within its rights to read the
> value of xp each time, compare it to a cached value, and use a cached
> value for '*xp' if 'xp' itself is still the same as the last time it
> was dereferenced.

Yes, I realized this declaration was declaring the pointer as volatile
rather than what it points to. But you're right, I didn't expect that
a particularly perverse compiler could circumvent that and still be
conformant. A very interesting point - thank you.

> > I don't think of this as a memory barrier issue. I want to capture
> > the value that the global 'x' has at the beginning of the function,
> > and guarantee that exactly that same value is used later in the
> > function. Any changes that happen to 'x', for whatever reason, while
> > the function is running must not be allowed to affect what the
> > function does, which should depend on the value that 'x' has at function
> > start and not any subsequent values.
>
> Any compiler that did not behave the way you describe would be
> horribly broken. Don't worry about it.
>
> > > This is all *way* outside the realm of Standard C, which does not
> > > support multiprocessing at all, and has quite limited support for
> > > interruptions (such as signals) in a single-processing model.
> >
> > Is it? I thought one of the reasons for having 'volatile' is
> > to enable such things as this in operating system code, which
> > is in fact the area of application in this case.
>
> What makes you think that the compiler is trying to optimize away a
> local variable that stores the value of a file-scope object?

Sadly, because it appears that this has happened in similar cases
and that caused difficult-to-discover bugs.

As for the compiler being broken - perhaps it is, but my belief is (if
there is no mention of 'volatile') the standard allows the compiler to
behave in this way and still be conformant.

> In any
> case, if the value of 'x' is subject to change while a function is
> executing, and that function does not write to 'x', write via a
> pointer that might alias to 'x', or call another function that might
> modify 'x', that means that the value of 'x' might change
> asynchronously and beyond the scope of the compiler.
>
> In that case, 'x' should be defined as volatile in the first place.

Oh, no argument there. It wasn't because of "practical considerations."
If you know what I mean.....

thanks again for the help!



Relevant Pages

  • Re: problem with memcpy and pointers/arrays confusion - again
    ... this second method is known as an explicit conversion, or cast. ... The cast, in effect, tells the compiler: ... the malloc function. ... function taking a size_t as a parameter and returning a void pointer (i.e. ...
    (comp.lang.c)
  • Re: Why the compiler applies sign extension to unsigned data?
    ... I want the value of p to be made unsigned *before* the cast. ... want the cast to generate a sign extension. ... ULONG_PTR is ULONG and casting the pointer to ULONG_PTR first is the ... on the compiler and on the knowledge of the size of the ptr variable, ...
    (microsoft.public.development.device.drivers)
  • Re: i386 nmi_watchdog: Merge check_nmi_watchdog fixes from x86_64
    ... > after the store without volatile it seems a reasonable ... > as we have taken the address earlier so at some point the compiler ... pointer away and will be referring to it later. ... or if the compiler does whole-program optimization and can see ...
    (Linux-Kernel)
  • Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
    ... If your compiler ... it works with a cast. ... Pointer arithmetic, as you probably know, is scaled by ... not sure about concerning realloc(). ...
    (comp.lang.c)
  • Re: Problem with malloc
    ... In C you need not cast void pointers. ... void pointer to any other pointer type. ... >> If your compiler pukes at that then you need a new ...
    (comp.lang.c)