volatile Info

S

Seebs

No? What about a free-standing implementation that defines the entry
point to be:
int run_c(volatile int pad_pressure, volatile struct point location);
Is that not permitted and relatively sane?

Someone else suggested this, but I haven't yet seen an actual instance of
any such thing -- while it would be possible, perhaps, I haven't heard of
any actual embedded systems doing it. I'm not sure that would make as
much sense as just declaring them as external objects.

-s
 
B

Ben Bacarisse

Seebs said:
Someone else suggested this,

That might have been me, if you mean in this thread. I seem to be alone
in thinking the concept is not entirely daft.
but I haven't yet seen an actual instance of
any such thing -- while it would be possible, perhaps, I haven't heard of
any actual embedded systems doing it. I'm not sure that would make as
much sense as just declaring them as external objects.

That a long way from suggesting that the concept does not really mean
anything! I agree that I've never seen it, but a language standard
exists to explain cases that we've not (yet) seen.
 
M

Malcolm McLean

So I think Scott's question stands: how is the
answer different _without_ the "volatile"? If there's some bizarre mechanism
by which the value of, uh, "value" could change, then the returned result
may not be be the square of the original argument.- Hide quoted text -
"volatile" is shorthand for "there is some bizarre mechanism by which
the value of this variable might change".
 
C

crisgoogle

"volatile" is shorthand for "there is some bizarre mechanism by which
the value of this variable might change".

Okay. But is the _absence_ of volatile shorthand for "there is NO
bizarre
mechanism by which the value of this variable might change"? I don't
think
so.

So I ask yet again: without the "volatile", how does the answer to the
original
question change?

(I tried to fix GG's quoting. Sorry if I failed).
 
S

Seebs

Okay. But is the _absence_ of volatile shorthand for "there is NO
bizarre
mechanism by which the value of this variable might change"? I don't
think
so.

Not exactly. It's shorthand for "any bizarre mechanism by which the
value of this variable might change means either that you've already
invoked undefined behavior or your implementation is not conforming."

-s
 
K

Keith Thompson

crisgoogle said:
Okay. But is the _absence_ of volatile shorthand for "there is
NO bizarre mechanism by which the value of this variable might
change"? I don't think so.

I do. The absence of "volatile" means that the value of the
variable will change only by mechanisms defined by the C program
(unless the program's behavior is undefined for some reason, in
which case all bets are off).
So I ask yet again: without the "volatile", how does the answer
to the original question change?

The function in question was roughly (changing the name of the
parameter for clarity):

int square(volatile int x) {
return x * x;
}

Given that x is declared volatile, it's theoretically possible
that the two references to x in the return statement could yield
different values because some outside entity changed x's value
during the evaluation of the expression. Also, accessing x is by
definition a side effect (see 5.1.2.3p2); this side effect could
affect the visible behavior of the program. For example, accessing
x might implicitly cause it to be incremented.

When I say that something is "theoretically possible", I merely mean
that if it did happen, it would not violate the requirements of the
Standard, not that it's at all likely to happen under some actual
non-DS9K implementation.

Consider the following program:

#include <stdlib.h>

int square(volatile int x) {
return x * x;
}

int main(void) {
return square(10) == 100 ? EXIT_SUCCESS : EXIT_FAILURE;
}

If this program returns an unsuccessful termination status to
the environment, that doesn't imply that the implementation is
non-conforming.

On the other hand, if a modified version of this program with the
"volatile" keyword deleted returns an unsuccessful termination status
to the environment, then the implementation *is* non-conforming.

"volatile" gives the implementation permission to cause a program
to behave in certain ways that it would not otherwise be permitted
to behave. An implementation is not obligated to take advantage
of this permission.

In this particular case, I'd be astonished if the "volatile"
keyword affected the visible behavior of the program (though it
might well affect the generated code). The authors of the standard,
quite rightly IMHO, did not restrict the use of "volatile" to cases
where it makes sense.
 
B

Ben Bacarisse

crisgoogle said:
Okay. But is the _absence_ of volatile shorthand for "there is NO
bizarre mechanism by which the value of this variable might change"? I
don't think so.

6.2.4 p2 includes this text:

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

and footnote 26 is:

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

so without the volatile qualifier, the only way the object's can change
is with an explicit store from the program.

<snip>
 
C

crisgoogle

The function in question was roughly (changing the name of the
parameter for clarity):

int square(volatile int x) {
    return x * x;

}

Given that x is declared volatile, it's theoretically possible
that the two references to x in the return statement could yield
different values because some outside entity changed x's value
during the evaluation of the expression.  Also, accessing x is by
definition a side effect (see 5.1.2.3p2); this side effect could
affect the visible behavior of the program.  For example, accessing
x might implicitly cause it to be incremented.

When I say that something is "theoretically possible", I merely mean
that if it did happen, it would not violate the requirements of the
Standard, not that it's at all likely to happen under some actual
non-DS9K implementation.

Consider the following program:

#include <stdlib.h>

int square(volatile int x) {
    return x * x;

}

int main(void) {
    return square(10) == 100 ? EXIT_SUCCESS : EXIT_FAILURE;

}

If this program returns an unsuccessful termination status to
the environment, that doesn't imply that the implementation is
non-conforming.

On the other hand, if a modified version of this program with the
"volatile" keyword deleted returns an unsuccessful termination status
to the environment, then the implementation *is* non-conforming.

"volatile" gives the implementation permission to cause a program
to behave in certain ways that it would not otherwise be permitted
to behave.  An implementation is not obligated to take advantage
of this permission.

In this particular case, I'd be astonished if the "volatile"
keyword affected the visible behavior of the program (though it
might well affect the generated code).  The authors of the standard,
quite rightly IMHO, did not restrict the use of "volatile" to cases
where it makes sense.

First off, I totally agree that this is all rather academic unless
you actually own a DS9K.

And I can't quite put my finger on what I'm trying to get at here,
so bear with me =)

Let's say that there _is_ some mechanism by which an object's value
may change, independently of what the abstract machine would otherwise
dictate. Modifying your example above:

<code>
/* assume that this is an implementation-defined memory-mapped
register that _ought_ to be treated as volatile. */
int *reg = 0x4000

#include <stdlib.h>

/* The parameter here _ought_ be declared as volatile. */
int square(int *x) {
return *x * *x;
}

int main(void) {
*reg = 10;
return square(reg) == 100 ? EXIT_SUCCESS : EXIT_FAILURE;
}
</code>

(I think I got that right).

In parallel to your explanation with your original example, I think
you're suggesting that the implementation is non-conforming if
this program returns EXIT_FAILURE.

Does this code exhibit undefined behaviour? Unless I made a mistake
or missed something, I don't think so (ignoring overflow,
as usual).

So it seems peculiar to me that the programmer can render the
implementation non-conforming by omitting the volatile in the
declaration of square().
 
K

Keith Thompson

crisgoogle said:
First off, I totally agree that this is all rather academic unless
you actually own a DS9K.

And I can't quite put my finger on what I'm trying to get at here,
so bear with me =)

Let's say that there _is_ some mechanism by which an object's value
may change, independently of what the abstract machine would otherwise
dictate. Modifying your example above:

<code>
/* assume that this is an implementation-defined memory-mapped
register that _ought_ to be treated as volatile. */
int *reg = 0x4000

Since there's no implicit conversion from int to int*, you need a cast
(and a semicolon):

int *reg = (int*)0x4000;

The behavior of accessing an int object at address 0x4000 is
undefined. There might not be accessible memory at that location;
dereferencing reg could easily cause the program to crash. (If you
don't think it's UB, feel free to show us where the standard defines
the behavior of accessing *(int*)0x4000.)
#include <stdlib.h>

/* The parameter here _ought_ be declared as volatile. */
int square(int *x) {
return *x * *x;
}

int main(void) {
*reg = 10;
return square(reg) == 100 ? EXIT_SUCCESS : EXIT_FAILURE;
}
</code>

(I think I got that right).

In parallel to your explanation with your original example, I think
you're suggesting that the implementation is non-conforming if
this program returns EXIT_FAILURE.

Does this code exhibit undefined behaviour? Unless I made a mistake
or missed something, I don't think so (ignoring overflow,
as usual).

I believe so; see above.
So it seems peculiar to me that the programmer can render the
implementation non-conforming by omitting the volatile in the
declaration of square().

That can't happen. If an object is volatile, any attempt to access it
without letting the compiler know it's volatile is either a constraint
violation or undefined behavior.
 
C

crisgoogle

Since there's no implicit conversion from int to int*, you need a cast
(and a semicolon):

Of course.
int *reg = (int*)0x4000;

The behavior of accessing an int object at address 0x4000 is
undefined.  There might not be accessible memory at that location;
dereferencing reg could easily cause the program to crash.  (If you
don't think it's UB, feel free to show us where the standard defines
the behavior of accessing *(int*)0x4000.)

So converting an integer to a pointer is, or at least may be,
implementation-defined, but then dereferencing that pointer is UB?
I believe so; see above.


That can't happen.  If an object is volatile, any attempt to access it
without letting the compiler know it's volatile is either a constraint
violation or undefined behavior.

So what it comes down to is: an object simply is, or is not, volatile,
regardless of how it is declared by the programmer? And if the object
_is_ volatile, but the programmer neglects to declare it as such,
the behaviour is undefined?

Obviously, this meshes with reality: above I referred to an object
that
_ought_ to be volatile, i.e., one that the programmer should define
as volatile in order to get the correct behaviour from the program.
It seems that you're saying this object _is_ volatile, regardless
of the presence or absence of the keyword.

I'm actually happy with this reasoning; like I said, it meshes with
reality. But I don't see in the Standard any definition of volatile
objects independent of the volatile keyword. Most references are
explicitly to "volatile-qualified type(s)", and though there are
a couple of references to "volatile objects", these seem to be
referring in fact to objects of volatile-qualified type, and
certainly are _not_ explicitly referring to "objects that _ought_
to be volatile" -- sorry, I don't have a better-but-short-enough
phrase to describe "objects that may change behind the
implementation's back". =)
 
K

Keith Thompson

crisgoogle said:
Of course.


So converting an integer to a pointer is, or at least may be,
implementation-defined, but then dereferencing that pointer is UB?

6.3.2.3p5:

An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined,
might not be correctly aligned, might not point to an entity
of the referenced type, and might be a trap representation.

I think that, even if the result is a trap representation, the
conversion itself doesn't invoke UB -- but then accessing the converted
value, even without dereferencing it, is UB.

In the absence of trap representations, yes, converting an integer to
a pointer is implementation-defined in most cases, but dereferencing
the result is usually undefined behavior.

[...]
So what it comes down to is: an object simply is, or is not, volatile,
regardless of how it is declared by the programmer? And if the object
_is_ volatile, but the programmer neglects to declare it as such,
the behaviour is undefined?

I think that's about right, yes. The volatility of an object is
determined by the implementation.
Obviously, this meshes with reality: above I referred to an object
that _ought_ to be volatile, i.e., one that the programmer should
define as volatile in order to get the correct behaviour from the
program. It seems that you're saying this object _is_ volatile,
regardless of the presence or absence of the keyword.

I'm actually happy with this reasoning; like I said, it meshes with
reality. But I don't see in the Standard any definition of volatile
objects independent of the volatile keyword. Most references are
explicitly to "volatile-qualified type(s)", and though there are
a couple of references to "volatile objects", these seem to be
referring in fact to objects of volatile-qualified type, and
certainly are _not_ explicitly referring to "objects that _ought_
to be volatile" -- sorry, I don't have a better-but-short-enough
phrase to describe "objects that may change behind the
implementation's back". =)

Perhaps "volatile objects" are considered to be outside the scope
of the standard. Or perhaps they're a concept that the standard
should mention, but doesn't.

Would anyone else care to chime in?
 
S

Shao Miller

Would anyone else care to chime in?
I believe that 'volatile' covers two cases.

In one case, it's a demand that the implementation evaluate any
expressions using the value of the object strictly according to the
semantics. If an implementation already does this, 'volatile' is
redundant in this case. (5.1.2.3,p8.)

In another case, it specifies that the object's value is not
guaranteed whatsoever. (5.1.2.3,p5 and 6.7.3,p6.) It's a "best
effort."

Keith's auto-increment is a simple example. It could be that one
wishes to count the read accesses to some object. This is out-of-
scope for C, so it must be achieved by some other means. Whatever
means is used to accomplish it might increment the value of the
object. Well now if we use that object at all without 'volatile', we
have no means to "admit" that the abstract machine can continue to
operate with defined behaviour; the value might change between
sequence points.
 
B

Ben Bacarisse

crisgoogle said:
So what it comes down to is: an object simply is, or is not, volatile,
regardless of how it is declared by the programmer? And if the object
_is_ volatile, but the programmer neglects to declare it as such,
the behaviour is undefined?

That may be so if the object is accessed in some way that puts it firmly
in the implementation's purview but not otherwise.

For example, if we know that a clock counter is available at address
0x400 or by using the external name __clock__ then we should write:

volatile int *count_ptr = (int *)0x400;

or

volatile int __clock__;

The C standard does not care what happens when the volatile keyword is
omitted in either of cases because the behaviour is down to the
implementation. But it does care in this case:

volatile int the_clock;

Without the volatile keyword, the_clock must hold the value the program
put in it or the implementation is not conforming. Names like this
could be used for such a purpose because the implementation can arrange
for the volatile nature of a declaration to be passed on to the linker
(if there is one). Volatile and non-volatile declarations could be
treated quite differently (the obvious way be some form on name
mangling: __the_clock for one and _vol__the_clock for the other).

I think this is, in part, why there has been such a strong feeling
against the notion of a volatile parameter. How can the implementation
preserve the correct meaning for ordinary parameters (i.e. that they
don't change value without explicit stores) and yet have those that are
declared volatile be subject to possible external change.

The same two ways out of the dilemma are available for volatile
parameters: either (a) the implementation is permitted to misbehave when
the keyword is omitted, or (b) there must be collusion between the
implementation and the agent that modifies the volatile objects so that
volatile and non-volatile parameters can be treated differently.

For example, in my start-up examples, the implementation might know that
the initial activation frame is at an address that the hardware maps to
changeable memory locations so the parameters /must/ be declared
volatile. This is an example of (a) above. A programmer who omits the
volatile keyword has already broken the contract with the
implementation.

In the garbage collection example, the implementation could arrange for
the stack to have markers to indicate which function calls have volatile
parameters and which don't. The GC could then scan the stack looking
for pointers that it might have to change. This an example of (b): the
implementation passes on enough information for ordinary parameters to
behave as they should.
Obviously, this meshes with reality: above I referred to an object
that
_ought_ to be volatile, i.e., one that the programmer should define
as volatile in order to get the correct behaviour from the program.
It seems that you're saying this object _is_ volatile, regardless
of the presence or absence of the keyword.

I'm actually happy with this reasoning; like I said, it meshes with
reality. But I don't see in the Standard any definition of volatile
objects independent of the volatile keyword. Most references are
explicitly to "volatile-qualified type(s)", and though there are
a couple of references to "volatile objects", these seem to be
referring in fact to objects of volatile-qualified type, and
certainly are _not_ explicitly referring to "objects that _ought_
to be volatile" -- sorry, I don't have a better-but-short-enough
phrase to describe "objects that may change behind the
implementation's back". =)

I think the standard gets it about right. I don't think there is an
easy solution that transfers the volatility to the object itself and
away from the name used to access it.
 
B

Ben Bacarisse

Kenneth Brody said:
On 8/6/2010 10:37 PM, Ben Bacarisse wrote:
[...]
For example, if we know that a clock counter is available at address
0x400 or by using the external name __clock__ then we should write:

volatile int *count_ptr = (int *)0x400;

or

volatile int __clock__;

The C standard does not care what happens when the volatile keyword is
omitted in either of cases because the behaviour is down to the
implementation. But it does care in this case:

volatile int the_clock;

Without the volatile keyword, the_clock must hold the value the program
put in it or the implementation is not conforming.

I disagree on that last part. If you leave off the "volatile" on an
object that can change through some external means, I think it comes
back to UB. (That is, you lied to the compiler, and all bets are off.)

Hmmm... That's an interesting way to look at it but can't agree that
it's right. This:

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

is a strictly conforming program and must print 42 on a conforming
implementation. If, for some peculiar reason, that is not possible
(because some mysterious external agent modifies 'the_clock') then I'd
say that a conforming implementation is not possible in that
environment.
Would you consider it "not conforming" if you lied a different way,
including "volatile", but not "int"?

volatile float the_clock;

I don't think this is the same. If there is an external agent that
provides a clock, then the documentation will tell you what type it
should be declared as, but drop the volatile and we have an ordinary
variable that should behave in a conforming way.
(Unless the definition were in a system-supplied header file, in which
case I would agree about not conforming.)

[...]
I think this is, in part, why there has been such a strong feeling
against the notion of a volatile parameter. How can the implementation
preserve the correct meaning for ordinary parameters (i.e. that they
don't change value without explicit stores) and yet have those that are
declared volatile be subject to possible external change.

Telling the compiler "the value of this object may change through some
external means", doesn't mean that this "external means" actually
exists.

True. I hope I did not imply that such an agent must exit. I certainly
didn't want to.
 
T

Tim Rentsch

crisgoogle said:
Okay. But is the _absence_ of volatile shorthand for "there is NO
bizarre mechanism by which the value of this variable might change"?
I don't think so.

So I ask yet again: without the "volatile", how does the answer to the
original question change?

The difference between having 'volatile' and not having it is
this. Given

int
square( /* not volatile */ int x ){
return x * x;
}

and assuming the rest of the program is strictly conforming, then
after a call 'square( 5 )' one (or more) of the following things
must be true:

1. The result will be 25; or

2. The implementation is non-conforming (assuming it's running
on its intended platform); or

3. There was some sort of hardware failure.

Conversely, given

int
square( volatile int x ){
return x * x;
}

and assuming the rest of the program is strictly conforming, then
after a call 'square( 5 )' one (or more) of the following things
must be true:

1. The result will be 25; or

2. The implementation is non-conforming (assuming it's running
on its intended platform); or

3. There was some sort of hardware failure; or

4. There was some effect caused by a volatile access.

So the difference between having 'volatile' and not having is
that, if the result isn't what the Standard semantics says it
should be, then our conclusions about what else might have
happened are weaker.

Note in particular that there isn't any change in the set of
possible outcomes, just a change in what we can conclude from an
outcome when it doesn't jibe with Standard-specified semantics.
 
R

Richard Bos

Ben Bacarisse said:
Hmmm... That's an interesting way to look at it but can't agree that
it's right. This:

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

is a strictly conforming program and must print 42 on a conforming
implementation. If, for some peculiar reason, that is not possible
(because some mysterious external agent modifies 'the_clock') then I'd
say that a conforming implementation is not possible in that
environment.

Ah. Strictly speaking, an implementation _includes_ the environment.
This POV can be taken to extremes (I don't think anyone sane would argue
that an implementation is non-conforming because an infinite loop can be
interrupted by a power cut, though I suspect some regulars here _would_
argue it), but nevertheless, in cases like this, there are arguments for
such a view.
I don't think this is the same. If there is an external agent that
provides a clock, then the documentation will tell you what type it
should be declared as, but drop the volatile and we have an ordinary
variable that should behave in a conforming way.

And the difference is? In both cases, using the wrong declaration leads
to undefined results. In one case, an int that changes value when it
shouldn't; in another, a volatile float that gets values it shouldn't.
I don't see why the Standard should make either case more, less, or even
differently undefined than the other.

Richard
 
T

Tim Rentsch

Ben Bacarisse said:
Hmmm... That's an interesting way to look at it but can't agree that
it's right. This:

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

is a strictly conforming program and must print 42 on a conforming
implementation. If, for some peculiar reason, that is not possible
(because some mysterious external agent modifies 'the_clock') then I'd
say that a conforming implementation is not possible in that
environment.

Ah. Strictly speaking, an implementation _includes_ the environment.
[snip]

Strictly speaking, it doesn't. The Standard distinguishes
between implementations and the 'computer system' on which an
implementation is run.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top