cast to volatile

G

google-newsgroups

Hello,

even (or because?) reading the standard (ISO/IEC 9899/1999) I do not
understand some issues with volatile. The background is embedded
programming where data is exchanged between main program flow and
interrupts.

At the organisation I work, instead of declaring a variable volatile,
it is casted to volatile when necessary:

Example 1 (reading):
int flag; // global variable, non-volatile
while( (volatile)flag ) // cast to volatile before reading
;

The reason for this is: when the variable is declared volatile, the
compiler cannot optimize it at all. However, by using the cast to
volatile, one can force volatile behavior in some areas, while others
(e.g. in the interrupt) still can be optimized. Addionally, this can be
used even if the variable declaration is not under my control.

Question: is this covered by the standard?

Since the whole topic of volatile is very complex (e.g. it is related
to pipeling), does somebody know a good article or book which covers
this topic deeply?

BTW, does anybody know how to google an expression like (volatile)
(*including* the bracket)?

Thanks,

Uli G. Margull

nospam@"lastname".de
 
T

Tim Rentsch

Hello,

even (or because?) reading the standard (ISO/IEC 9899/1999) I do not
understand some issues with volatile. The background is embedded
programming where data is exchanged between main program flow and
interrupts.

At the organisation I work, instead of declaring a variable volatile,
it is casted to volatile when necessary:

Example 1 (reading):
int flag; // global variable, non-volatile
while( (volatile)flag ) // cast to volatile before reading
;

The reason for this is: when the variable is declared volatile, the
compiler cannot optimize it at all. However, by using the cast to
volatile, one can force volatile behavior in some areas, while others
(e.g. in the interrupt) still can be optimized. Addionally, this can be
used even if the variable declaration is not under my control.

This method doesn't do what you want, which is to say it doesn't
force volatile semantics. Use this instead:

while( *(volatile*) &flag ) ...

Question: is this covered by the standard?

Yes, although perhaps not as directly as it might.

Since the whole topic of volatile is very complex (e.g. it is related
to pipeling), does somebody know a good article or book which covers
this topic deeply?

A small set of rules for using volatile:

1. Use volatile for variables that might change "unexpectedly".

2. Use volatile for automatic variables in routines that use
setjmp().

3. To force volatile semantics on a particular access, take the
address of the variable and cast it to (volatile WHATEVER *),
dereferencing the cast expression to get the value.

4. Sometimes volatile is a reasonable way to get around problems
with code generation in compilers that have conformance
problems in some areas, eg, the gcc compiler on x86 with
semantics of assigning or casting to double. Don't do
this just haphazardly, since if it's unnecessary code
quality will very likely go down.

5. Unless you really know what you're doing and why you're
doing it, if you're using volatile you're likely doing
something wrong. Try to find another way to solve the
problem, and if you still have to use volatile code
up a nice small example and post to comp.lang.c and
ask for helpful suggestions.
 
T

Tim Rentsch

Tim Rentsch said:
This method doesn't do what you want, which is to say it doesn't
force volatile semantics. Use this instead:

while( *(volatile*) &flag ) ...

Of course what I meant to write was

while( *(volatile int*) &flag ) ...
 
L

Lawrence Kirby

Hello,

even (or because?) reading the standard (ISO/IEC 9899/1999) I do not
understand some issues with volatile. The background is embedded
programming where data is exchanged between main program flow and
interrupts.

At the organisation I work, instead of declaring a variable volatile,
it is casted to volatile when necessary:

Example 1 (reading):
int flag; // global variable, non-volatile
while( (volatile)flag ) // cast to volatile before reading
;

I assume you mean the cast (volatile int)flag. This doesn't do what you
want. The special behaviour of the const and volatile qualifiers only
applies to lvalues (although type rules apply in other situations). What
the code above does is read the value of flag using non-volatile semantics
then casts that value to volatile int. Since it 9is just a value at this
point and not an lvalue the volatile has no effect. The line is equivalent
to

while (flag)

You would have to write something like

while (*(volatile int *)&flag)

to do what you want. Here the *lvalue* used to read the value of flag has
type volatile int.
The reason for this is: when the variable is declared volatile, the
compiler cannot optimize it at all. However, by using the cast to
volatile, one can force volatile behavior in some areas, while others
(e.g. in the interrupt) still can be optimized.

The whole concept of using a volatile variable as non-volatile in some
areas sounds dangerous. You would probably be better off using a separate
variable for parts that don't need to be volatile. That could make the
compiler optimiser's job easier too.
Addionally, this can be
used even if the variable declaration is not under my control.

It sounds like an odd situation. A variable being used in this way should
be defined as volatile. If it isn't that suggests the code defining it
isn't designed for this purpose and probably won't work properly.
Question: is this covered by the standard?

The standard specifies volatile
Since the whole topic of volatile is very complex (e.g. it is related
to pipeling), does somebody know a good article or book which covers
this topic deeply?

volatile itself has nothing to do with pipelining. How volatile might be
implemented on specific architectures is a machine code level topic. If
you are writing in C you let the compiler handle the details.

Also consider the sig_atomic_t type.

Lawrence
 
G

google-newsgroups

Thanks for your answers sofar. In the meantime, I tested the problem on
a PowerPC platform with a Wind River compiler, with the following
results:

int dummy = 0;

1.
unsigned char flag;
while( (volatile)flag)
dummy++;

The above does not work: the memory is not reloaded in the evaluation

2.
unsigned char flag;
while( (volatile unsigned char)flag )
dummy++;

The above does work: the memory is reloaded every time

3.
unsigned int flag;
while( (volatile unsigned char)flag )
dummy++;

The above does not work: the memory is not reloaded.

At the moment, the proposed solution in the company is to use the
second one (volatile unsigned char), but I see problems with conformity
to ANSI-C.

Thanks again & regards,

Uli Margull
 
T

Tim Rentsch

pete said:
Doesn't (volatile*) mean the same thing as (volatile int*)?

Yes I believe it does, but in C99 I think it may require a diagnostic.
In any case I consider '(volatile int*)' to be better style.
 
L

Lawrence Kirby

Thanks for your answers sofar. In the meantime, I tested the problem on
a PowerPC platform with a Wind River compiler, with the following
results:

int dummy = 0;

1.
unsigned char flag;
while( (volatile)flag)
dummy++;

A non-volatile access of flag
The above does not work: the memory is not reloaded in the evaluation

2.
unsigned char flag;
while( (volatile unsigned char)flag )
dummy++;

Another non-volatile access of flag
The above does work: the memory is reloaded every time

A compiler may choose to implement any object access as volatile if it
wishes, however that doesn't make the code correct.
3.
unsigned int flag;
while( (volatile unsigned char)flag )
dummy++;

Agaon, a non-volatile access of flag.
The above does not work: the memory is not reloaded.

At the moment, the proposed solution in the company is to use the second
one (volatile unsigned char), but I see problems with conformity to
ANSI-C.

A couple of people have given a correct solution, why are you considering
3 wrong solutions and ignoring that?

And, again, consider using sig_atomic_t for the integer type.

Lawrence
 
P

pete

Tim said:
Yes I believe it does, but in C99 I think it may require a diagnostic.
In any case I consider '(volatile int*)' to be better style.

Thank you.
I think so too.

I think it's best to write in a style constrained by both
C89 and C99.

int main(void){return 0;}
instead of
main(){return 0;}
or
int main(void){}
 
G

google-newsgroups

Hi Lawrence,

thank you everybody for writing your discussion topics, and I assure
you that I am not ignoring any post.

In the company I work (it's a rather big one), the coding guidelines
state that the "cast" to (volatile int) is the correct way to access a
variable that might change from outside (e.g. due to ISR).

In order to change that rule, I do not only have to know what is right
or wrong, but I need an rock-solid argument proving my opinion.
Basically, I have to argue out of the standard. However, I personally
have a hard time reading this from the standard.

Again, thanks for all your posts, and I am not ignoring them.

Yours,

Uli Margull
 
T

Tim Rentsch

In the company I work (it's a rather big one), the coding guidelines
state that the "cast" to (volatile int) is the correct way to access a
variable that might change from outside (e.g. due to ISR).

In order to change that rule, I do not only have to know what is right
or wrong, but I need an rock-solid argument proving my opinion.
Basically, I have to argue out of the standard. However, I personally
have a hard time reading this from the standard.

I recommend the Rationale document ("Rationale for International
Standard--Programming Languages--C"). In particular, if people
need convincing, quote this paragraph out of section 6.7.3 of the
Rationale document:

A cast of a value to a qualified type has no effect; the
qualification (volatile, say) can have no effect on the access
sinceit has occurred prior to the case. 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 that pointer.

Notice the last sentence. In other words, use:

* (volatile WHATEVER *) & non_volatile_object_identifier

The paragraph in question is just before section 6.7.3.1 in the
rationale document. If you also need to quote from the standard
document itself, cite 6.7.3 p3:

The properties associated with qualified types are meaningful
only for expressions that are lvalues.

The expression

(volatile WHATEVER) non_volatile_object_identifier

is _not_ an lvalue, hence the 'volatile' qualifier is meaningless.
Conversely, the expression

* (volatile WHATEVER *) & non_volatile_object_identifier

_is_ an lvalue (it may be placed on the left side of an assignment
statement), so the property of the 'volatile' qualifier has its
intended meaning in this case.
 
G

google-newsgroups

Hi Tim,

thanks a lot. I think this solved my problem.

Now I am looking forward to some interesting discussions here...

Yours,

Uli
 
C

Chris Torek

Thanks for your answers sofar. In the meantime, I tested the problem on
a PowerPC platform with a Wind River compiler ...

It may be worth noting that there is more than one Wind River
compiler for PowerPC platforms. This is about all that is
at least marginally on-topic here; the rest probably belongs
in comp.os.vxworks.

[In all three examples, "flag" is a non-volatile object, which
will presumably be modified from an interrupt handler. The first
two make it an "unsigned char" and the third an "unsigned int".]
while( (volatile)flag) [does not work as desired]
while( (volatile unsigned char)flag ) [does work as desired]
while( (volatile unsigned char)flag ) [does not work as desired]
At the moment, the proposed solution in the company is to use the
second one (volatile unsigned char), but I see problems with conformity
to ANSI-C.

While none of these is "nonstandard", the fact that the second one
happens to work under whatever conditions you have used to test it
is probably mere coincidence.

The *best* solution is to declare "flag" as volatile in the first
place. The second best is to use *(volatile T *)&flag, where T
stands for the actual type of "flag" (unsigned char or unsigned int).
The former will work on all the Wind River compilers, and the latter
will work in all the cases I am aware of (which is nowhere near
"all").
 

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

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top