Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Use of volatile const

18 views
Skip to first unread message

Ian Collins

unread,
Apr 14, 2008, 5:55:08 PM4/14/08
to
My understanding of a variable declared "volatile const" is read only,
but the value may change. A typical use would be a read only bit device,
say a timer counter.

Are the semantics of "volatile const" well defined if the variable is
assigned a value? For example, can the compiler optimise away the
access to the variable and substitute the constant value in the
following code?

#include <stdio.h>

volatile const unsigned z = 42;

int main(void)
{
printf("%d\n", z );
}

--
Ian Collins.

Douglas A. Gwyn

unread,
Apr 14, 2008, 10:03:05 PM4/14/08
to
Ian Collins wrote:
> My understanding of a variable declared "volatile const" is read only,
> but the value may change. A typical use would be a read only bit device,
> say a timer counter.

Yes. "Volatile" means "every read/write access specified in the
code must actually occur -- no caching" while "const" means "read
only -- no modification allowed".

> Are the semantics of "volatile const" well defined if the variable is
> assigned a value?

Not if it is actually an assignment (see below), since there is
a semantic requirement being violated. An object declared with
const qualification must not be written to by the program. (In
fact, the compiler might assign it to read-only memory and an
attempt to modify it might result in a trap.)

> For example, can the compiler optimise away the
> access to the variable and substitute the constant value in the
> following code?

The compiler can do whatever it wants once you have invoked
undefined behavior or otherwise failed to comply with the
requirements imposed by the standard.

However, your example does *not* assign to the variable. The
"42" is an *initializer* and the value is placed into the
variable before the C program execution begins. Usually this
is done at link time, although other schemes are sometimes used.

> #include <stdio.h>
> volatile const unsigned z = 42;
> int main(void)
> {
> printf("%d\n", z );
> }

That appears to strictly conform to C99 and must print "42".
I personally would have used %u and would have returned 0
explicitly.

Ian Collins

unread,
Apr 14, 2008, 10:30:30 PM4/14/08
to
Douglas A. Gwyn wrote:

> Ian Collins wrote:
>
>> For example, can the compiler optimise away the
>> access to the variable and substitute the constant value in the
>> following code?
>
> However, your example does *not* assign to the variable. The
> "42" is an *initializer* and the value is placed into the
> variable before the C program execution begins.

Good point.

>> #include <stdio.h>
>> volatile const unsigned z = 42;
>> int main(void)
>> {
>> printf("%d\n", z );
>> }
>
> That appears to strictly conform to C99 and must print "42".

Yes, but which 42? The constant 42, or the value of z?

--
Ian Collins.

Brian Inglis

unread,
Apr 15, 2008, 2:01:40 AM4/15/08
to

Is there any rule prohibiting custom application initialization or
environmental aliasing connecting the externally visible location z with
(say) an ISR in the environment which updates the location occupied by
z? If z was not global, and its address never passed to another
function, I'd agree z's value could be assumed to remain 42.

--
Thanks. Take care, Brian Inglis Calgary, Alberta, Canada

Brian....@CSi.com (Brian[dot]Inglis{at}SystematicSW[dot]ab[dot]ca)
fake address use address above to reply

Richard Tobin

unread,
Apr 15, 2008, 7:21:21 AM4/15/08
to
In article <48040CD9...@null.net>,

Douglas A. Gwyn <DAG...@null.net> wrote:

>> #include <stdio.h>
>> volatile const unsigned z = 42;
>> int main(void)
>> {
>> printf("%d\n", z );
>> }

>That appears to strictly conform to C99 and must print "42".

Since it is declared volatile, why can it not be modified by the
hardware before the call to printf()?

The standard has the example:

extern const volatile int real_time_clock;

Clearly in this case we are supposed to imagine that we are linking
to some library which defines real_time_clock to be a hardware register,
but does the fact that z is initialized prevent that from happening here?

-- Richard

--
:wq

Ian Collins

unread,
Apr 15, 2008, 7:51:01 AM4/15/08
to
The argument made to me was that because it was initialised in the same
compilation unit as it was used, the semantics were unclear and the
compiler was free to optimise away the variable access. Note in the
example I posted, the variable was not declared extern.

I tend to disagree, some processors have write once registers with read
only bits, so they can (must) be initialised, but they are read only and
volatile to the code.

My question is, are the semantics of volatile fully defined in this case?

--
Ian Collins.

Richard Tobin

unread,
Apr 15, 2008, 9:37:53 AM4/15/08
to
In article <66jj54F...@mid.individual.net>,
Ian Collins <ian-...@hotmail.com> wrote:

>Note in the
>example I posted, the variable was not declared extern.

As far as I can see, the standard makes no distinction between

volatile const unsigned z = 42;

and
extern volatile const unsigned z = 42;

(they are both definitions with external linkage) so the difference
between your example and the one in the standard is the
initialization, which makes it definition rather merely a declaration.

But I see nothing that says that having a definition rather than a
declaration for a volatile variable prevents it from being changed by
the hardware.

(The obvious way to make the real_time_clock example work is to have
some non-C code do the work of the definition and cause the object to
be in the relevant memory-mapped location, but that's just an
implementation detail.)

-- Richard
--
:wq

James Kuyper

unread,
Apr 15, 2008, 12:12:57 PM4/15/08
to
Richard Tobin wrote:
> In article <66jj54F...@mid.individual.net>,
> Ian Collins <ian-...@hotmail.com> wrote:
>
>> Note in the
>> example I posted, the variable was not declared extern.
>
> As far as I can see, the standard makes no distinction between
>
> volatile const unsigned z = 42;
> and
> extern volatile const unsigned z = 42;
>
> (they are both definitions with external linkage) so the difference
> between your example and the one in the standard is the
> initialization, which makes it definition rather merely a declaration.
>
> But I see nothing that says that having a definition rather than a
> declaration for a volatile variable prevents it from being changed by
> the hardware.

I've argued that this is allowed by the actual wording in the standard,
even though it is unlikely that this was the intent of the authors. The
only words that describe what being volatile means, say that this
meaning applies to any volatile-qualified object; they should apply
equally well to either definition of z.

I was told that the intent of the authors was more important than the
words that they actually wrote in an attempt to express that intent. I
was told that any failure of those words to clearly express that intent
could be easily overcome by applying common sense, and that it was
therefore unnecessary to change them.

> (The obvious way to make the real_time_clock example work is to have
> some non-C code do the work of the definition and cause the object to
> be in the relevant memory-mapped location, but that's just an
> implementation detail.)

I'm fairly certain that the intent of the authors was that
truly-volatile memory could only occur under certain circumstances. The
example using real_time_clock is one obvious way; special routines that
return pointers to volatile-qualified memory is another. However, I have
no idea what the standardese would look like which makes this
distinction; the only thing I know is that the standard as currently
written does not make that distinction.

lawrenc...@siemens.com

unread,
Apr 15, 2008, 10:39:36 AM4/15/08
to
Ian Collins <ian-...@hotmail.com> wrote:
>
> My question is, are the semantics of volatile fully defined in this case?

The semantics of volatile are *never* fully defined by the standard --
the details are all implementation defined.

-Larry Jones

I wonder if I can grow fangs when my baby teeth fall out. -- Calvin

Keith Thompson

unread,
Apr 15, 2008, 12:16:10 PM4/15/08
to

There's no difference, as long as it prints the characters '4', '2',
and '\n'.

However, I'm not convinced that Doug has got this one right. The
object z could be modified in some implementation-defined manner
between its initialization and the printf call; for example, a
compiler or linker option might be used to specify that the object
named "z" is associated with a real-time clock or hardware RNG, so any
value could be printed (and of course you should use "%u" rather than
"%d").

--
Keith Thompson (The_Other_Keith) <ks...@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

David R Tribble

unread,
Apr 16, 2008, 9:48:23 PM4/16/08
to
Ian Collins wrote:
>> #include <stdio.h>
>> volatile const unsigned z = 42;
>> int main(void)
>> {
>> printf("%d\n", z );
>> }
>

Douglas A. Gwyn wrote:
>> That appears to strictly conform to C99 and must print "42".
>

Ian Collins wrote:
> Yes, but which 42? The constant 42, or the value of z?

I would think that the semantics of 'volatile' prohibit optimizing
away any reference to z, whether it's const or not.

Otherwise allowing a compiler to optimize away accesses
to z (because it's const) would violate the semantics
of 'volatile'.

So the printf() call should print whatever the value of z is
at the time of the call.

-drt

Anagrams of "violate" and "volatile" differ by only one letter.

Douglas A. Gwyn

unread,
Apr 18, 2008, 8:54:41 PM4/18/08
to
Keith Thompson wrote:
> However, I'm not convinced that Doug has got this one right. The
> object z could be modified in some implementation-defined manner

But we know it isn't, because without the "volatile" the semantics
of the code are specified by the standard, and they are not affected
by the further qualification. It is unfortunate that the standard
was phrased in terms of "may be modified by ghosts" instead of "must
be physically read and written in strict accordance with the abstract
mashine model", which is the actual intent. Generally you have to
resort to non-strictly-conforming code to invoke any ghosts:
*(volatile short *)0xFFFF0FE0; // activates ghost controller

Douglas A. Gwyn

unread,
Apr 18, 2008, 9:02:18 PM4/18/08
to
Richard Tobin wrote:
> The standard has the example:
> extern const volatile int real_time_clock;
> Clearly in this case we are supposed to imagine that we are linking
> to some library which defines real_time_clock to be a hardware register,
> but does the fact that z is initialized prevent that from happening here?

The standard's example is, as you say, incompletely specified.
In fact my standalone PDP-11 C library does use a global that
is updated by clock interrupts, although I picked a name from
the namespace reserved for the implementation. The example
was intended to hint at the behavior without going into too
much detail.

*If* the main program under discussion happened to be linked
with a module that modifies z asynchronously, then indeed the
printed value might not be 42. I assumed all along that the
complete program had been provided to us.

Douglas A. Gwyn

unread,
Apr 18, 2008, 8:57:52 PM4/18/08
to
Brian Inglis wrote:
> Is there any rule prohibiting custom application initialization or
> environmental aliasing connecting the externally visible location z with
> (say) an ISR in the environment which updates the location occupied by
> z?

Since without the volatile qualification the answer is yes, it is
prohibited (in a conforming implementation), and the qualification
only affects the access pattern in the generated code, I'd say that
it would be quite a feat for the implementation to manage to key
off the changed access pattern to start acting weird about z.

Douglas A. Gwyn

unread,
Apr 18, 2008, 9:04:53 PM4/18/08
to
James Kuyper wrote:
> ... However, I have

> no idea what the standardese would look like which makes this
> distinction; the only thing I know is that the standard as currently
> written does not make that distinction.

The standard already specifies that the accesses must actually
occur, *whether or not a ghost is at work*.

James Kuyper

unread,
Apr 18, 2008, 10:58:35 PM4/18/08
to

True; but that's not the issue. The issue is what the access will find;
because the standard allows for (as you put it) ghostly intervention,
the access may retrieve a different value from the one last written.
There's no reasonable way for that to happen, but the standard only
requires that the object's definition be volatile-qualified, in order to
allow "ghostly intervention". It doesn't impose other requirements, such
as initializing a pointer to volatile qualified memory with an
implementation-defined special value, or with the return value from an
implementation-defined routine. It simply says "volatile qualified".

Keith Thompson

unread,
Apr 19, 2008, 1:26:07 AM4/19/08
to

I'm still not convinced.

C99 6.2.4p2 says:

An object exists, has a constant address, and retains its
last-stored value throughout its lifetime.

with a footnote:

In the case of a volatile object, the last store need not be
explicit in the program.

C99 6.7.3p6 says:

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, as described in 5.1.2.3. Furthermore, at every sequence
point the value last stored in the object shall agree with that
prescribed by the abstract machine, except as modified by the
unknown factors mentioned previously. What constitutes an access
to an object that has volatile-qualified type is
implementation-defined.

It seems clear to me that both the literal wording and the intent of
the standard allow a volatile object's value to be modified behind the
program's back "in ways unknown to the implementation".

Douglas A. Gwyn

unread,
Apr 22, 2008, 3:52:50 PM4/22/08
to
Keith Thompson wrote:
> It seems clear to me that both the literal wording and the intent of
> the standard allow a volatile object's value to be modified behind the
> program's back "in ways unknown to the implementation".

Yes, I know all about the wording. It is expressed in an unfortunate
manner. The intended idea is that the *programmer* takes responsibility
by using the "volatile" qualifier, telling the compiler that it is not
allowed to rearrange (or otherwise optimize) so-qualified accesses.
One reason, but not the only reason, might be that there are external
forces at work affecting the object in ways that the compiler is unaware of.

Douglas A. Gwyn

unread,
Apr 22, 2008, 3:57:32 PM4/22/08
to
James Kuyper wrote:

> Douglas A. Gwyn wrote:
> > The standard already specifies that the accesses must actually
> > occur, *whether or not a ghost is at work*.
> True; but that's not the issue. The issue is what the access will find;
> because the standard allows for (as you put it) ghostly intervention,
> the access may retrieve a different value from the one last written.
> There's no reasonable way for that to happen, but the standard only
> requires that the object's definition be volatile-qualified, in order to
> allow "ghostly intervention". It doesn't impose other requirements, such
> as initializing a pointer to volatile qualified memory with an
> implementation-defined special value, or with the return value from an
> implementation-defined routine. It simply says "volatile qualified".

My point is that the rest of the standard is still applicable,
and it includes a virtual machine model, sequence points, etc.
Volatile qualification, which can be applied in ways other than
just in object definitions, limits the extent to which the
generated code can deviate from the abstract execution model.

I didn't understand your last couple of sentences, since I never
said anything about implementation-defined special values etc.

Keith Thompson

unread,
Apr 22, 2008, 6:35:21 PM4/22/08
to
"Douglas A. Gwyn" <DAG...@null.net> writes:
> James Kuyper wrote:
>> Douglas A. Gwyn wrote:
>> > The standard already specifies that the accesses must actually
>> > occur, *whether or not a ghost is at work*.
>> True; but that's not the issue. The issue is what the access will find;
>> because the standard allows for (as you put it) ghostly intervention,
>> the access may retrieve a different value from the one last written.
>> There's no reasonable way for that to happen, but the standard only
>> requires that the object's definition be volatile-qualified, in order to
>> allow "ghostly intervention". It doesn't impose other requirements, such
>> as initializing a pointer to volatile qualified memory with an
>> implementation-defined special value, or with the return value from an
>> implementation-defined routine. It simply says "volatile qualified".
>
> My point is that the rest of the standard is still applicable,
> and it includes a virtual machine model, sequence points, etc.
> Volatile qualification, which can be applied in ways other than
> just in object definitions, limits the extent to which the
> generated code can deviate from the abstract execution model.

Ok, so volatile does two different things.

(1) It requires accesses to the object to take place as specified by
the abstract machine (I think we're all in agreement on that).

(2) It allows the object's value to be "modified in ways unknown to
the implementation" (C99 6.7.3p6).

For example:

#include <stdio.h>
volatile int x = 42;
int main(void)
{
printf("x = %d\n", x);
return 0;
}

(1) means that the printf call must actually access the current value
of x; the compiler may not replace the call with puts("x = 42"), as it
could in the absence of the volatile keyword.

(2) means that the value printed may be something other than 42 in a
conforming implementation.

If you agree, then I don't see a problem; in particular, I don't see
how the wording of the standard is "expressed in an unfortunate
manner", as you wrote in another followup in this thread.

If you don't agree (either with (1) or with (2)), then you're
disagreeing with the plain wording of the standard, unless I'm missing
something. If the standard were ambiguous, I'd probably accept your
statement about the intent, but I just don't see any ambiguity here.

james...@verizon.net

unread,
Apr 22, 2008, 6:51:13 PM4/22/08
to
Douglas A. Gwyn wrote:
> James Kuyper wrote:
> > Douglas A. Gwyn wrote:
> > > The standard already specifies that the accesses must actually
> > > occur, *whether or not a ghost is at work*.
> > True; but that's not the issue. The issue is what the access will find;
> > because the standard allows for (as you put it) ghostly intervention,
> > the access may retrieve a different value from the one last written.
> > There's no reasonable way for that to happen, but the standard only
> > requires that the object's definition be volatile-qualified, in order to
> > allow "ghostly intervention". It doesn't impose other requirements, such
> > as initializing a pointer to volatile qualified memory with an
> > implementation-defined special value, or with the return value from an
> > implementation-defined routine. It simply says "volatile qualified".
>
> My point is that the rest of the standard is still applicable,
> and it includes a virtual machine model, sequence points, etc.
> Volatile qualification, which can be applied in ways other than
> just in object definitions, limits the extent to which the
> generated code can deviate from the abstract execution model.

What that rest of the standard says about the virtual machine model,
sequence points, etc, is not sufficient to ensure that the following
code has defined behavior:

int main(void) {int i=0; return i;}

Only 6.2.4p2 guarantees that, when the return statement is reached,
'i' will retain it's last-stored value, in this case 0, which is a
value with defined behavior for a return statement. However, 6.7.3p6
explicitly modifies that guarantee with respect to any object with
volatile-qualified type. As Footnote 26 puts it, "In the case of a


volatile object, the last store need not be explicit in the program."

This means that in principle

int main(void) {volatile int i=0; return i;}

might not have defined behavior, because a store which is not
explicitly in the program might have changed the value of 'i' to one
which cannot be safely used in a return statement.

> I didn't understand your last couple of sentences, since I never
> said anything about implementation-defined special values etc.

I was just giving examples of plausible ways in which a program could
gain access to truly-volatile memory. My point is, the standard should
clarify what those methods are. As written it says that simply
applying the 'volatile' qualifier to an object declaration is
sufficient to enable stores which are not explicit in the program; and
I'm sure that this was not the intent.

Keith Thompson

unread,
Apr 22, 2008, 8:47:09 PM4/22/08
to
james...@verizon.net writes:
[...]

> I was just giving examples of plausible ways in which a program could
> gain access to truly-volatile memory. My point is, the standard should
> clarify what those methods are. As written it says that simply
> applying the 'volatile' qualifier to an object declaration is
> sufficient to enable stores which are not explicit in the program; and
> I'm sure that this was not the intent.

Perhaps that's the point that I'm missing. *Why* are sure that's not
the intent? Or to put it another way, why shouldn't it be the intent?

It seems reasonable to me to say that a volatile object can be
modified in ways that aren't explicit in the program. It doesn't seem
reasonable to me for the standard to have anything to say about what
those ways are.

If I write:

#include <stdio.h>
volatile int x = 42;
int main(void)
{


printf("x = %d\n", x);
return 0;
}

maybe I can specify a linker option that causes an object named "x" to
be associated with some hardware or OS entity. The ways in which an
object can be modified outside the control of the program are
inherently implementation-specific; it seems to me that it's not up to
the standard to specify how that's done, or how it can't be done.

In short, I don't see any problem with the standard's current wording.

James Kuyper

unread,
Apr 23, 2008, 8:55:15 AM4/23/08
to

The standard seems to be mixing two different concepts: the primary
meaning of 'volatile' is simply that it inhibits optimizations that rely
upon the object's value being immune to external change. The other
meaning is that it also exposes objects to such changes. I think that
while every object so exposed must be volatile-qualified, automatically
exposing every object so qualified to arbitrary change is a bad idea.

The standard already identifies two contexts where volatile-qualified
objects are sometimes needed: communication with signal handlers and
longjmp(). However, in both cases the usefulness of the volatile
qualified objects depends upon strict limits on how they can change.

Communication with a signal handler requires that the signal handler and
the other code it is communicating with be the only things which can
change the values of the volatile-qualified objects they share access to.

After a call to longjmp(), volatile-qualified objects local to function
where setjmp() was called should only have been been modified by code
within that function, or by other functions which have been given
volatile-qualified pointers to those local objects.

If volatile qualification alone is sufficient to also expose those
objects to changes by other means, then it renders both of those two
applications of 'volatile' unportable. There are already too many
barriers to portable use of signal handles; we don't need any more.

The standard can and should specify some limits on how an object can
become exposed to changes that render volatile-qualification necessary.

Richard Tobin

unread,
Apr 23, 2008, 9:52:58 AM4/23/08
to
In article <TkGPj.10942$aq4.8339@trnddc02>,

James Kuyper <james...@verizon.net> wrote:
>The standard seems to be mixing two different concepts: the primary
>meaning of 'volatile' is simply that it inhibits optimizations that rely
>upon the object's value being immune to external change. The other
>meaning is that it also exposes objects to such changes. I think that
>while every object so exposed must be volatile-qualified, automatically
>exposing every object so qualified to arbitrary change is a bad idea.

I'm not sure what you mean by "exposing" an object to such change. I
don't think that Keith was suggesting that the volatile declaration
*causes* the variable to be subject to change. It doesn't give the
compiler the right to randomly change it for example. It informs the
compiler that the variable *is* exposed to external change, and a
consequence of that is that the compiler cannot perform certain
optimisations. The cause of the exposure is somewhere else - code
in a signal handler, or linkage to a hardware register for example.

-- Richard
--
:wq

Keith Thompson

unread,
Apr 23, 2008, 11:54:59 AM4/23/08
to

I think it's not a problem so much from the compiler's point of view
as from the programmer's point of view. As a programmer I might want
to declare an object in such a way that accesses to it are not
optimized away, but I might still want a guarantee that its current
value is the most recent value *I* stored into it. In practice, if I
just add the volatile keyword to the declaration, I can be reasonably
confident of this (unless I do some system-specific thing to allow it
to be changed behind my back, like tying it to a system clock
register). But in principle, there are no guarantees; storing 42 into
my variable might trigger some other action, and I might get something
other than 42 when I read it.

On the other hand, sometimes you *want* to allow an object to be
arbitrarily modified.

Ideally, perhaps there should be two separate mechanisms, one to
inhibit optimizations and another to allow behind-the-scenes changes
and arbitrary side effects. But in the absence of a new keyword, I
can't think of a good way to limit the effects of "volatile" without
taking away existing functionality.

james...@verizon.net

unread,
Apr 23, 2008, 1:24:15 PM4/23/08
to
Richard Tobin wrote:
> In article <TkGPj.10942$aq4.8339@trnddc02>,
> James Kuyper <james...@verizon.net> wrote:
> >The standard seems to be mixing two different concepts: the primary
> >meaning of 'volatile' is simply that it inhibits optimizations that rely
> >upon the object's value being immune to external change. The other
> >meaning is that it also exposes objects to such changes. I think that
> >while every object so exposed must be volatile-qualified, automatically
> >exposing every object so qualified to arbitrary change is a bad idea.
>
> I'm not sure what you mean by "exposing" an object to such change. I
> don't think that Keith was suggesting that the volatile declaration
> *causes* the variable to be subject to change. It doesn't give the
> compiler the right to randomly change it for example. ...

I believe that the standard allows precisely that. If you replace
"randomly" with "under implementation-specifc circumstances", then I
believe that Keith would be in agreement with me on that point. Every
message he's posted on this thread has made some reference to such a
possibiity:

Date: Tue, 15 Apr 2008 09:16:10 -0700: "The object z could be modified
in some implementation-defined manner between its initialization and
the printf call; ..."

Date: Fri, 18 Apr 2008 22:26:07 -0700: 'It seems clear to me that both


the literal wording and the intent of the standard allow a volatile

object's value to be modified behind the program's back "in ways
unknown to the implementation".'

Date: Tue, 22 Apr 2008 15:35:21 -0700: "(2) means that the value


printed may be something other than 42 in a
conforming implementation."

IDate: Tue, 22 Apr 2008 17:47:09 -0700: "t seems reasonable to me to


say that a volatile object can be modified in ways that aren't
explicit in the program."


> ... It informs the


> compiler that the variable *is* exposed to external change, and a
> consequence of that is that the compiler cannot perform certain

> optimisations. ...

This is the first meaning I describe above.

> ... The cause of the exposure is somewhere else - code


> in a signal handler, or linkage to a hardware register for example.

While that is almost certainly the committee's intent, and the way all
real implementations probably work, I believe that the actual wording
of the standard falls short of actually requiring this to be the case.
I don't think the standard should specify a particular API or anything
like that; I just think it should just provide enough limitations that
I don't have to worry, not even in theory, about the possibility of
external modifications to the values of volatile-qualified objects I
might use in a function that calls setjmp(), or to communicate with a
signal handler.

For me, this is purely of theoretical interest; for the last dozen
years I've been working on a project where setjmp() and signal
handlers are not only unnecessary, but actively prohibited in
delivered code, under the terms of our contract with our client.

Keith Thompson

unread,
Apr 23, 2008, 5:36:48 PM4/23/08
to
james...@verizon.net writes:
> Richard Tobin wrote:
>> In article <TkGPj.10942$aq4.8339@trnddc02>,
>> James Kuyper <james...@verizon.net> wrote:
>> >The standard seems to be mixing two different concepts: the primary
>> >meaning of 'volatile' is simply that it inhibits optimizations that rely
>> >upon the object's value being immune to external change. The other
>> >meaning is that it also exposes objects to such changes. I think that
>> >while every object so exposed must be volatile-qualified, automatically
>> >exposing every object so qualified to arbitrary change is a bad idea.
>>
>> I'm not sure what you mean by "exposing" an object to such change. I
>> don't think that Keith was suggesting that the volatile declaration
>> *causes* the variable to be subject to change. It doesn't give the
>> compiler the right to randomly change it for example. ...
>
> I believe that the standard allows precisely that. If you replace
> "randomly" with "under implementation-specifc circumstances", then I
> believe that Keith would be in agreement with me on that point. Every
> message he's posted on this thread has made some reference to such a
> possibiity:
[snip]

Yes. In fact, it could literally be "randomly" if you use some
implementation-specific method to associate a given volatile object
with a source of physically generated random numbers.

[...]

> While that is almost certainly the committee's intent, and the way all
> real implementations probably work, I believe that the actual wording
> of the standard falls short of actually requiring this to be the case.
> I don't think the standard should specify a particular API or anything
> like that; I just think it should just provide enough limitations that
> I don't have to worry, not even in theory, about the possibility of
> external modifications to the values of volatile-qualified objects I
> might use in a function that calls setjmp(), or to communicate with a
> signal handler.

Ok, so what you'd like is a guarantee that this:

#include <stdio.h>
volatile int x = 42;
int main(void)
{

printf("%d\n", x);
return 0;
}

will actually print 42 (in addition to the requirement that the value
of x must actually be accessed). Or at least that it will print 42
*unless* you do something implementation-specific to cause "x" to
change behind your back.

On the other hand, something like this:

volatile unsigned *ptr = (unsigned*)0xdeadbeef;

could cause *ptr to behave in arbitrarily odd ways. (For that matter,
even without volatile something else could write to address
0xdeadbeef.)

I think the idea we're trying to express is that volatile-qualified
objects don't change behind your program's back *unless* you do
something implementation-specific to enable them to do so. The
standard doesn't currently make this guarantee, and expressing it in
standardese would be non-trivial. Perhaps it would make sense to
relegate the additional guarantee to a non-normative footnote, where
it doesn't have to be quite so rigorous.

Richard Tobin

unread,
Apr 23, 2008, 7:21:30 PM4/23/08
to
In article <23fbc7d4-1c2d-4b84...@w74g2000hsh.googlegroups.com>,
<james...@verizon.net> wrote:

>> I'm not sure what you mean by "exposing" an object to such change. I
>> don't think that Keith was suggesting that the volatile declaration
>> *causes* the variable to be subject to change. It doesn't give the
>> compiler the right to randomly change it for example. ...

>I believe that the standard allows precisely that. If you replace
>"randomly" with "under implementation-specifc circumstances", then I
>believe that Keith would be in agreement with me on that point. Every
>message he's posted on this thread has made some reference to such a
>possibiity:
>
>Date: Tue, 15 Apr 2008 09:16:10 -0700: "The object z could be modified
>in some implementation-defined manner between its initialization and
>the printf call; ..."
>
>Date: Fri, 18 Apr 2008 22:26:07 -0700: 'It seems clear to me that both
>the literal wording and the intent of the standard allow a volatile
>object's value to be modified behind the program's back "in ways
>unknown to the implementation".'
>
>Date: Tue, 22 Apr 2008 15:35:21 -0700: "(2) means that the value
>printed may be something other than 42 in a
>conforming implementation."
>
>IDate: Tue, 22 Apr 2008 17:47:09 -0700: "t seems reasonable to me to
>say that a volatile object can be modified in ways that aren't
>explicit in the program."

And the idea in all these cases is that it gets changed because of
something else you did, apart from declaring it volatile, such as
linking it to a hardware register. If you hadn't declared it volatile
it would have changed anyway, but because you didn't tell the compiler
it might not notice.

>> ... The cause of the exposure is somewhere else - code
>> in a signal handler, or linkage to a hardware register for example.
>
>While that is almost certainly the committee's intent, and the way all
>real implementations probably work, I believe that the actual wording
>of the standard falls short of actually requiring this to be the case.

C99 says that a volatile object "may be modified in ways unknown to
the implementation or have other unknown side effects". If the
implementation arranged for volatile variables to be changed randomly,
it wouldn't be unknown to it. If it was the implementation that was
changing it, then it wouldn't "therefore [have to evaluate
expressions] strictly according to the rules of the abstract machine",
because it would know when it changed it. The whole paragraph
only makes sense if it's something else that's changing the object.

-- Richard
--
:wq

Wojtek Lerch

unread,
Apr 23, 2008, 9:46:44 PM4/23/08
to
"Richard Tobin" <ric...@cogsci.ed.ac.uk> wrote in message
news:fuog9q$nnu$1...@pc-news.cogsci.ed.ac.uk...

> C99 says that a volatile object "may be modified in ways unknown to
> the implementation or have other unknown side effects". If the
> implementation arranged for volatile variables to be changed randomly,
> it wouldn't be unknown to it. If it was the implementation that was
> changing it, then it wouldn't "therefore [have to evaluate
> expressions] strictly according to the rules of the abstract machine",
> because it would know when it changed it. The whole paragraph
> only makes sense if it's something else that's changing the object.

Imagine an implementation whose startup code compares the names of all the
environment variables provided to the program with all the names of volatile
objects with external linkage defined in the program. For each match found,
if the value of environment variable looks like a hexadecimal encoding of a
valid machine address, the matching volatile object is mapped to a hardware
register at that address. The rest of volatile objects are mapped to normal
memory. The implementation has no knowledge of how the behaviour of a
hardware register depends on its address.

Is this a conforming implementation? If not, which requirement of the
standard does it violate?

James Kuyper

unread,
Apr 24, 2008, 5:27:38 AM4/24/08
to
Keith Thompson wrote:
...

> I think the idea we're trying to express is that volatile-qualified
> objects don't change behind your program's back *unless* you do
> something implementation-specific to enable them to do so. The
> standard doesn't currently make this guarantee, and expressing it in
> standardese would be non-trivial. ...

Yes, thank you. That is precisely what I'm trying to say. If the
implementation-specific things were restricted to the source code, such
as calling a particular function, or #including a particular header, or
using a #pragma, or initializing a pointer from an
implementation-specific integral value, it would be non-trivial, but
possible, to come up with suitable wording. I think there's only one
barrier that would make it impossible.

I believe that you've implied that the implementation-specific thing
that could trigger this might be a command-line option passed to the
compiler, presumably something like: -mmap shared_array, which would
make the volatile-qualified variable with external linkage named
shared_array be shareable with other processes.

The problem with this is that the thing which enables this feature is
external to the program. The standard is, as a matter of deliberate
design, written entirely in terms of the relationship between the
sequence of characters that make up the source code, and the behavior
that is specified by that sequence of characters.

As a result, compiler command line options fall into two categories:
those that choose between different implementation-defined or undefined
behaviors that a conforming implementation is free to choose, and
options that render the implementation non-conforming when chosen.

If the standard were modified to provide any meaningful guarantees that
I would allow me to write source code using volatile-qualified variables
without worrying about external changes to those variables, then a
command-line option that was sufficient, in itself, to turn off those
guarantees would have to make the compiler non-conforming when selected.
I would prefer it if the normal methods for exposing a variable to
external change could all be handled without rendering the
implementation non-conforming.

> ... Perhaps it would make sense to


> relegate the additional guarantee to a non-normative footnote, where
> it doesn't have to be quite so rigorous.

Personally, I'd prefer more rigor.

Richard Tobin

unread,
Apr 24, 2008, 6:03:04 AM4/24/08
to
In article <67a745F...@mid.individual.net>,
Wojtek Lerch <Wojt...@yahoo.ca> wrote:

I don't see anything non-conforming about, though it doesn't seem very
sensible. But I also don't see why it contradicts what you quoted
above: you had to set an environment variable to get the location
mapped to a register.

I'm willing to admit that if you stretch the standard's language you
can probably justify almost any odd bahviour here, as in many other
places. In which case it's just a quality-of-implementation issue;
the standard is clear enough that no sensible implementation should
defeat the natural uses of volatile.

-- Richard
--
:wq

Wojtek Lerch

unread,
Apr 24, 2008, 9:14:28 AM4/24/08
to
"Richard Tobin" <ric...@cogsci.ed.ac.uk> wrote in message
news:fuplso$13n4$1...@pc-news.cogsci.ed.ac.uk...

No, I didn't; the system has set it for me. As it turns out, all the
programs that come with the system use a convention where the variable
"volatile time_t nticks", if defined, is mapped to a hardware register in a
clock chip that allows them to get the current system time much more
efficiently than by calling time(). When the OS was being installed, the
"nticks" environment variable was set up for everybody to point to the
correct address of the clock chip. This is documented somewhere, but I have
never read that part of my system's documentation. I have never even
noticed that I have an environment variable named "nticks". This system is
not Unix -- it doesn't use environment variables for anything other than
mapping your volatile variables to hardware registers, and everybody
familiar with this system knows that messing with your environment variables
is neither safe nor interesting.

Now imagine that I have found this cool program on the Internet that is
supposed to be portable to any system that supports C99 and the Unix alarm()
function. The program compiles on my system just fine, but when I run it,
it dies horribly. As it turns out after days of debugging, it's because the
program happens to define a "volatile sig_atomic_t nticks" to count how many
times a signal handler has run. Whose fault is that -- the program's or the
implementation's?

> I'm willing to admit that if you stretch the standard's language you
> can probably justify almost any odd bahviour here, as in many other
> places. In which case it's just a quality-of-implementation issue;
> the standard is clear enough that no sensible implementation should
> defeat the natural uses of volatile.

No, it's also an issue of how wide the category of strictly portable
programs is. If your interpretation is correct, a strictly portable program
cannot define an ordinary object with a volatile type and assume that its
value can't possibly change except when changed by the program. And if the
next release of my imaginary implementation is free to apply its magic to
automatic volatile objects without losing conformance to C99, that means
that the promises that the standard seems to make about the use of volatile
in the context of longjmp() cannot be relied on in strictly conforming code,
either.

Wojtek Lerch

unread,
Apr 24, 2008, 1:40:00 PM4/24/08
to
"Keith Thompson" <ks...@mib.org> wrote in message
news:87r6cwt...@kvetch.smov.org...

> I think the idea we're trying to express is that volatile-qualified
> objects don't change behind your program's back *unless* you do
> something implementation-specific to enable them to do so. The
> standard doesn't currently make this guarantee, and expressing it in
> standardese would be non-trivial.

I don't know; I like the idea that the implementation-specific thing must
either be done by the program, or must render the implementation
non-conforming. I would like to have the simple guarantee that an object
defined by the program, volatile or not, preserves its last value stored by
the program, and the only ways to enable external "ghosts" that may modify
the object behind the program's back are by using a non-conforming
implementation or by doing something that makes the program's behaviour
officially undefined by the C standard, such as calling a function not
written in standard C, or converting an integer to a pointer, or declaring
an object with a name that belongs to the reserved namespace. (Notice that
the above can easily be translated to standardese by deleting the part that
starts with "and the only ways", all the way to the end.)

This would restrict the usefulness of "volatile" in portable code to the two
situations were "volatile" is specifically required by the standard (one
involving signal handlers and the other longjmp()), but I think that given
that all other uses of "volatile" are not portable anyway, that would be
better than making those two standard uses of "volatile", along with any
other uses, officially non-portable by allowing conforming implementations
to arbitrarily interfere with volatiles in a program unless you have made
sure that you don't happen to have something implementation-specific in your
environmant that enables the "ghosts".

(Perhaps we could reach a compromise by inventing three categories of
implementations: conforming without "ghosts", conforming with "ghosts", and
non-conforming. If an implementation with "ghosts" can indeed be
conforming, then I would want the standard to require that the presence of
"ghosts" in the implementation must be documented. Also, I'd invent a new
category for programs that aren't strictly conforming but would be if there
were no "ghosts".)


Francis Glassborow

unread,
Apr 25, 2008, 8:52:57 AM4/25/08
to


So exactly how would you program in C for hardware with memory mapped
i/o ports? That, IIUC was one of the main motives for introducing
'volatile' as a keyword.

Francis Glassborow

unread,
Apr 25, 2008, 8:59:59 AM4/25/08
to
Wojtek Lerch wrote:

> Now imagine that I have found this cool program on the Internet that is
> supposed to be portable to any system that supports C99 and the Unix
> alarm() function. The program compiles on my system just fine, but when
> I run it, it dies horribly. As it turns out after days of debugging,
> it's because the program happens to define a "volatile sig_atomic_t
> nticks" to count how many times a signal handler has run. Whose fault
> is that -- the program's or the implementation's?
>

Neither. It is yours for not understanding the constraints of the
platform you are using. BTW, how does the loader know that nticks even
exists in your program? Well only because the implementation has somehow
passed that information on. It really is the responsibility of the
programmer (especially those using code written by someone else on some
other hardware) to know the details of volatile on the platform being used.

Wojtek Lerch

unread,
Apr 25, 2008, 12:55:10 PM4/25/08
to
"Francis Glassborow" <francis.g...@btinternet.com> wrote in message
news:EYydnSp2RdexSYzV...@bt.com...

> Wojtek Lerch wrote:
>> (Perhaps we could reach a compromise by inventing three categories of
>> implementations: conforming without "ghosts", conforming with "ghosts",
>> and non-conforming. If an implementation with "ghosts" can indeed be
>> conforming, then I would want the standard to require that the presence
>> of "ghosts" in the implementation must be documented. Also, I'd invent a
>> new category for programs that aren't strictly conforming but would be if
>> there were no "ghosts".)
>
> So exactly how would you program in C for hardware with memory mapped i/o
> ports?

Exactly the same way you do today, I imagine. You'd know the address of the
port from somewhere, as an integer value, and then convert it to a pointer
to a volatile type. Or you would call some implementation-specific function
that would return a pointer. Or maybe you would include an
implementation-specific header containing the declaration of a
volatile-qualified object, and then you'd access that object.

But not by defining a volatile-qualified object in your code and then using
some mechanism outside of the code to map that object to hardware. That's
the only way I'm uncomfortabe with. I have never heard of a system where
that's how you do it. I don't want the standard to forbid mapping memory
locations to hardware registers, only to forbid mapping objects *defined by
the program* unless the program explicitly requests that by using some
implementation-specific mechanism.

(Sorry if I wasn't clear enough about what exactly I was referring to by
"ghosts". I wasn't talking about all possible mechanisms that might modify
what look like memory locations behind the program's back. I was only
talking about mechanisms that detect volatile-qualified objects *defined by
the program*, and modify them behind the program's back, *without* any
encouragement in the program's code.)


Wojtek Lerch

unread,
Apr 25, 2008, 12:55:49 PM4/25/08
to
"Francis Glassborow" <francis.g...@btinternet.com> wrote in message
news:3sSdnSljtZVJSIzV...@bt.com...

> Wojtek Lerch wrote:
>
>> Now imagine that I have found this cool program on the Internet that is
>> supposed to be portable to any system that supports C99 and the Unix
>> alarm() function. The program compiles on my system just fine, but when
>> I run it, it dies horribly. As it turns out after days of debugging,
>> it's because the program happens to define a "volatile sig_atomic_t
>> nticks" to count how many times a signal handler has run. Whose fault is
>> that -- the program's or the implementation's?
>>
> Neither. It is yours for not understanding the constraints of the platform
> you are using.

So basically what you're saying is that the promises the standard appears to
be making about the usefullness of volatile-qualified object in the context
of signals and longjmp() are not really general guarantees that can be
relied on by strictly conforming code, because they're subject to the
constraints of the platform? Why does the standard even bother to talk
about them then, instead of letting implementations make their own promises
based on their constraints?

Keith Thompson

unread,
Apr 25, 2008, 4:30:00 PM4/25/08
to

Then you need to define what "defined by the program" means.

I think what you mean is that any declared object (of either static or
automatic storage duration), or any subcomponent of such an object, is
defined by the program. An object created by malloc() probably should
qualify as well, since an implementation messing with such an object
makes no more sense than messing with an explicitly declared object.
But an object obtained by some implementation-specific method, such as
``*ptr'' given:

volatile unsigned char *ptr = (unsigned char*)0xdeadbeef;

is not, and the implementation is free to mess with it.

On the other hand, I don't think we want to forbid an implementation
from playing games with declared object via an implementation-defined
#pragma (which is already allowed to do just about anything).

Wojtek Lerch

unread,
Apr 25, 2008, 4:59:19 PM4/25/08
to
"Keith Thompson" <ks...@mib.org> wrote in message
news:878wz1s...@kvetch.smov.org...
> "Wojtek Lerch" <Wojt...@yahoo.ca> writes:
>> ... I don't want the

>> standard to forbid mapping memory locations to hardware registers,
>> only to forbid mapping objects *defined by the program* unless the
>> program explicitly requests that by using some implementation-specific
>> mechanism.
>
> Then you need to define what "defined by the program" means.

Sorry, I didn't think that was unclear... "Object X is defined in the
program" == "A definition for object X exists in the program". A definition
of an object is a declaration that reserves storage for the object (6.7#5).
I said "defined" rather than "declared" because I wanted to exclude objects
that are provided by a library and the program merely declares them.

> I think what you mean is that any declared object (of either static or
> automatic storage duration), or any subcomponent of such an object, is
> defined by the program. An object created by malloc() probably should
> qualify as well, since an implementation messing with such an object
> makes no more sense than messing with an explicitly declared object.

Yes, I should have included those, thanks.

> But an object obtained by some implementation-specific method, such as
> ``*ptr'' given:
>
> volatile unsigned char *ptr = (unsigned char*)0xdeadbeef;
>
> is not, and the implementation is free to mess with it.

Of course. The result of the conversion is implementation-defined, and
quite likely does not point to any of the objects defined in the program.
Another example could be a pointer returned by the POSIX mmap().

> On the other hand, I don't think we want to forbid an implementation
> from playing games with declared object via an implementation-defined
> #pragma (which is already allowed to do just about anything).

Of course. If you use a non-standard pragma, the implementation gets to
pick which promises of the standard it wants to keep.

0 new messages