473,802 Members | 1,937 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Volatiles in assignment expressions

Hi!

I tried to post this to comp.lang.c.mod erated but it didn't
seem to go through.

I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;

...

if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a. I would have assumed that only one
read access should be performed. Does the standard allow the
second read operation?

I am adding a lot of standard texts that I've used when trying
to deduce the answer. Please help if you can!

Sorry for the long posting!

Regards
/Daniel W

P.s. Remove underscores from e-mail address if replying via
e-mail!

------------------------------------------------------------
Reading from the standard ISO/IEC [9899:1999] I find the
following passages related to this issue (A denotes the
rationale and B denotes the standard):

B.5.1.2.3 - 2 "Accessing a volatile object, modifying an object,
modifying a file, or calling a function that does any of those
operations are all side effects, which are changes in the state
of the execution environment. Evaluation of an expression may
produce side effects. At certain specified points in the execution
sequence called sequence points, all side effects of previous
evaluations shall be complete and no side effects of subsequent
evaluations shall have taken place." ...

B.6.5.16 - 3 "An assignment operator stores a value in the
object designated by the left operand. An assignment expression
has the value of the left operand after the assignment, but is
not an lvalue. The type of an assignment expression is the type
of the left operand unless the left operand has qualified type,
in which case it is the unqualified version of the type of the
left operand. The side effect of updating the stored value of
the left operand shall occur between the previous and the next
sequence point."

B.6.5.16.2 - 3 "A compound assignment of the form E1 op= E2
differs from the simple assignment expression E1 = E1 op E2 only
in that the lvalue E1 is evaluated only once."

B.6.3.2.1 - 2 "Except when it is the operand of the sizeof operator,
the unary & operator, the ++ operator, the -- operator, or the left
operand of the . operator or an assignment operator, an lvalue that
does not have array type is converted to the value stored in the
designated object (and is no longer an lvalue). If the lvalue have
qualified type, the value has the unqualified version of the type
of the lvalue; otherwise, the value has the type of the lvalue. If
the lvalue has an incomplete type and does not have array type, the
behavior is undefined."

B.6.5.3.1 - 2 "The value of the operand of the prefix ++ operator
is incremented. The result is the new value of the operand after
incrementation. The expression ++E is equivalent to (E+=1). See
discussions of additive operators and compound assignment for
information on constraints, types, side effects, and conversions
and the effects of operations on pointers."

B.6.7.3 - 3 "The properties associated with qualified types are
meaningfull only for expressions that are lvalues."

B.6.7.3 - 6 "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 refering to such
an object shall be evaulated strictly according to the rules of
the abstract machine, as described in 5.1.2.3. Furthermore, at
every sequence point the value 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
implementetion-defined."

Annex C in the standard places a sequnce point after the controlling
expression of a selection statement.

A.6.5.2.4 "The C89 Committee did not endorse the practice in some
implementations of considering post-increment and post-decrement
operator expressions to be lvalues."

A.6.5.3.1 "See 6.5.2.4."

A.6.5.16 "The optimization rules for factoring out assignments can
also be stated. Let X(i,S) be an expression which contains no
impure functions or sequenced operators, and suppose that X
contains a storage S(i) to i which sets i to Snew(i) and returns
Sval(i). The possible expressions are

S(i): Sval(i): Snew(i):
++i i+1 i+1
i++ i i+1
--i i-1 i-1
i-- i i-1
y y y
i op= y i op y i op y

Then X(i,S) can be replaced by either

(T = i, i = Snew(i), X(T,Sval))

or

(T = X(i,Sval), i = Snew(i), T)

provided that neither i nor y have side effects themselves."
Mar 7 '06 #1
13 1951
Daniel W <_R*********@ho tmail.com> writes:
I tried to post this to comp.lang.c.mod erated but it didn't
seem to go through.


Articles appear on comp.lang.c.mod erated when the moderator gets
around to posting them. Yours will probably show up eventually (long
after your question has been answered to death here).

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Mar 7 '06 #2


Daniel W wrote On 03/07/06 10:17,:

I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;

...

if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a. I would have assumed that only one
read access should be performed. Does the standard allow the
second read operation?
[...]

Reading from the standard ISO/IEC [9899:1999] I find the
following passages related to this issue (A denotes the
rationale and B denotes the standard):
[...]
B.6.5.16 - 3 "An assignment operator stores a value in the
object designated by the left operand. An assignment expression
has the value of the left operand after the assignment, but is
not an lvalue. [...]


This seems to be where the ambiguity creeps in: must
"the value ... after the assignment" be read from the
volatile l.h.s. (seems to be gcc's interpretation) , or
will the value assigned to the l.h.s. suffice (yours)?

The gcc reading seems defensible: "after" means "after,"
after all. Maybe the variable is really a special hardware
gadget that's connected up to an I/O device: You write a
command code to it, and when you read from it you get back
not what was written, but some kind of device status. That
is, the value as read might not resemble the value written.

--
Er*********@sun .com

Mar 7 '06 #3
On 2006-03-07, Daniel W <_R*********@ho tmail.com> wrote:
Hi!

I tried to post this to comp.lang.c.mod erated but it didn't
seem to go through.

I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;

...

if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a.
That's because for some reason gcc chooses to read a again. However, the
C code only includes ONE read access - to read the original value which
is incremented. R2 <- R1 would probably have been more in the spirit of
the meaning of the original expression, since the prefix ++ operator
yields a specific value, not an alias for its argument. However, since
it results in the same behavior it is permitted.

Besides, the RTL code given is five statements, each presumably with its
own rtl analogue of a "sequence point", not one.
I would have assumed that only one read access should be performed.
Does the standard allow the second read operation?


The standard does not govern gcc's "RTL" language. There is only one
read access in the C code shown.
Mar 7 '06 #4

"Eric Sosman" <Er*********@su n.com> wrote in message
news:du******** **@news1brm.Cen tral.Sun.COM...


Daniel W wrote On 03/07/06 10:17,:

I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;

...

if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a. I would have assumed that only one
read access should be performed. Does the standard allow the
second read operation?
[...]

Reading from the standard ISO/IEC [9899:1999] I find the
following passages related to this issue (A denotes the
rationale and B denotes the standard):
[...]
B.6.5.16 - 3 "An assignment operator stores a value in the
object designated by the left operand. An assignment expression
has the value of the left operand after the assignment, but is
not an lvalue. [...]


This seems to be where the ambiguity creeps in: must
"the value ... after the assignment" be read from the
volatile l.h.s. (seems to be gcc's interpretation) , or
will the value assigned to the l.h.s. suffice (yours)?

The gcc reading seems defensible: "after" means "after,"
after all. Maybe the variable is really a special hardware
gadget that's connected up to an I/O device: You write a
command code to it, and when you read from it you get back
not what was written, but some kind of device status. That
is, the value as read might not resemble the value written.


The ambiguity here, if there is one, becomes more obvious if we consider f =
(g = h), with g volatile. Should the value assigned to f be that of h
(converted to the type of g, then converted to the type of f), as it would
be if g were not volatile, or can it be an unrelated value read back from g?

--
RSH
Mar 7 '06 #5
Jordan Abel wrote:
On 2006-03-07, Daniel W <_R*********@ho tmail.com> wrote:

I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;
...
if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a.


That's because for some reason gcc chooses to read a again. However, the
C code only includes ONE read access - to read the original value which
is incremented. R2 <- R1 would probably have been more in the spirit of
the meaning of the original expression, since the prefix ++ operator
yields a specific value, not an alias for its argument. However, since
it results in the same behavior it is permitted.


Actually it may not result in the same behavior, since volatile accesses
can have side effects outside explicit code. Volatile accesses are
often used for hardware registers. Some registers do not return the
last value written, while others might have initiate hardware actions
caused by reading the location.

As far as Standard C is concerned, ++a is equivalent to a += 1, which
returns the value of the left operand after assignment. It could be
argued that the only way to know the value of a volatile object is to
read it, even though it has just been written! In any case, what
qualifies as an access to a volatile object is implementation-defined,
and can differ from one implementation to another, but must be
documented. This gives, I think, leeway regarding how many read
accesses there are in ++a.

In summary, a conforming compiler is allowed to make another access to
a, as long as it is documented.

--
Thad
Mar 8 '06 #6
Robin Haigh wrote:
"Eric Sosman" <Er*********@su n.com> wrote in message
news:du******** **@news1brm.Cen tral.Sun.COM...

Daniel W wrote On 03/07/06 10:17,:
I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;

...

if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a. I would have assumed that only one
read access should be performed. Does the standard allow the
second read operation?
[...]

Reading from the standard ISO/IEC [9899:1999] I find the
following passages related to this issue (A denotes the
rationale and B denotes the standard):
[...]
B.6.5.16 - 3 "An assignment operator stores a value in the
object designated by the left operand. An assignment expression
has the value of the left operand after the assignment, but is
not an lvalue. [...]


This seems to be where the ambiguity creeps in: must
"the value ... after the assignment" be read from the
volatile l.h.s. (seems to be gcc's interpretation) , or
will the value assigned to the l.h.s. suffice (yours)?

The gcc reading seems defensible: "after" means "after,"
after all. Maybe the variable is really a special hardware
gadget that's connected up to an I/O device: You write a
command code to it, and when you read from it you get back
not what was written, but some kind of device status. That
is, the value as read might not resemble the value written.

The ambiguity here, if there is one, becomes more obvious if we consider f =
(g = h), with g volatile. Should the value assigned to f be that of h
(converted to the type of g, then converted to the type of f), as it would
be if g were not volatile, or can it be an unrelated value read back from g?


Whan about the rationale (A.6.5.3.1) that states that the value
of an assignment expression should not be an lvalue? A friend of
mine said that it could be interpreted such that it is the lvalue
to rvalue conversion that is the actual read operation. If so, gcc
would be in error.

/Daniel
Mar 8 '06 #7
Thad Smith wrote:
Jordan Abel wrote:
On 2006-03-07, Daniel W <_R*********@ho tmail.com> wrote:


I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;
...
if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a.

That's because for some reason gcc chooses to read a again. However, the
C code only includes ONE read access - to read the original value which
is incremented. R2 <- R1 would probably have been more in the spirit of
the meaning of the original expression, since the prefix ++ operator
yields a specific value, not an alias for its argument. However, since
it results in the same behavior it is permitted.

Actually it may not result in the same behavior, since volatile accesses
can have side effects outside explicit code. Volatile accesses are
often used for hardware registers. Some registers do not return the
last value written, while others might have initiate hardware actions
caused by reading the location.

As far as Standard C is concerned, ++a is equivalent to a += 1, which
returns the value of the left operand after assignment. It could be
argued that the only way to know the value of a volatile object is to
read it, even though it has just been written! In any case, what
qualifies as an access to a volatile object is implementation-defined,
and can differ from one implementation to another, but must be
documented. This gives, I think, leeway regarding how many read
accesses there are in ++a.

In summary, a conforming compiler is allowed to make another access to
a, as long as it is documented.


Yes, but the rationale (A.6.5.16 see original posting) clearely
states two possible rewrites of an assignment operation and the
one apliccable to ++a is given as:

(T = X(i,Sval), i = Snew(i), T)

This would indicate that the only legal rewrite is to introduce
a temporary and that the it is the value of the temporary that
is "exposed". If this is true, then gcc would be in error. I'm
not pretending to be an expert on the standard so I may be in
gross error here.

/Daniel
Mar 8 '06 #8
Jordan Abel wrote:
On 2006-03-07, Daniel W <_R*********@ho tmail.com> wrote:
Hi!

I tried to post this to comp.lang.c.mod erated but it didn't
seem to go through.

I've got a question about volatiles in assignment expressions.
I found the following code snippet in an embedded development
forum:

----
volatile char a;

...

if (++a == 1)
{
...
----

This code snippet was then followed by the output from two
compilers, one which was gcc. Gcc's code looked like something
like this (in RTL like form where Rn denotes a register):

R1 <- *a
R1 <- R1 + 1
*a <- R1
R2 <- *a
IF R2 == 1

Now to my question! The code above contains two read accesses
and one write access to a.

That's because for some reason gcc chooses to read a again. However, the
C code only includes ONE read access - to read the original value which
is incremented. R2 <- R1 would probably have been more in the spirit of
the meaning of the original expression, since the prefix ++ operator
yields a specific value, not an alias for its argument. However, since
it results in the same behavior it is permitted.


It is also my interpretation of the C code; one read and one write.
If the volatile variable is a hardware register, then the result
might not be the same and therein lies the dilemma.
Besides, the RTL code given is five statements, each presumably with its
own rtl analogue of a "sequence point", not one.

I would have assumed that only one read access should be performed.
Does the standard allow the second read operation?

The standard does not govern gcc's "RTL" language. There is only one
read access in the C code shown.


Hmmm... The "RTL code" that I wrote was just an abstraction of the
actual instructions issued by gcc. Regardless of this, the generated
object code should match the behavior of the C virtual machine and
it is there that it seems to break down. My interpretation says one
read and one write whereas gcc produces two reads and one write.

/Daniel
Mar 8 '06 #9
>On 2006-03-07, Daniel W <_R*********@ho tmail.com> wrote:
[given]
volatile char a;
...
if (++a == 1)
[gcc chooses to load, add, store, load again, and then compare,
i.e., re-read "a" after writing it in case the computed "old a
plus 1" is not still stored in "a".]

In article <sl************ ***********@ran dom.yi.org>
Jordan Abel <ra*******@gmai l.com> wrote:That's because for some reason gcc chooses to read a again. However, the
C code only includes ONE read access - to read the original value which
is incremented.


This is not clear, or at least, not to me. (It happens to be what
I would *prefer*, but the model in the C standards is a bit vague.)
I believe the most important sentence, however, is this one from
6.5.3 of a C99 draft:

What constitutes an access to an object that has
volatile-qualified type is implementation-defined.

In other words, gcc can do anything at all here, provided what
it does is documented.

Note that you can get the desired effect -- whichever effect is
actually desired -- with:

volatile char a;
char tmp;

tmp = a; /* one read from "a" */
a = tmp + 1; /* one write to "a" */
if (tmp == 0) /* no re-reading of "a" */

or:

tmp = a; /* one read from "a" */
a = tmp + 1; /* one write to "a" */
if (a == 1) /* re-read "a" in case it is not equal to tmp+1 */

or of course any number of equivalent code fragments.

Note also that on machines that have read/modify/write bus cycles,
there is no guarantee that operations like:

*p |= val;

use an R/M/W cycle: this might still use separate load and store
operations. If you need control that fine, you must either get
a guarantee from your implementation, or resort to assembly code.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 8 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
3240
by: Paul Rubin | last post by:
OK, I want to scan a file for lines matching a certain regexp. I'd like to use an assignment expression, like for line in file: if (g := re.match(pat, line)): croggle(g.group(1)) Since there are no assignment expressions in Python, I have to use a temp var. That's a little more messy, but bearable:
10
3324
by: Andrew Koenig | last post by:
It has been pointed out to me that various C++ books disagree about the relative precedence of ?: and the assignment operators. In order to satisfy myself about the matter once and for all, I looked at the grammar in the C++ standard. The relative fragments are as follows: conditional-expression: logical-or-expression logical-or-expression ? expression : assignment-expression
6
13387
by: Neil Zanella | last post by:
Hello, I would like to know whether the following C fragment is legal in standard C and behaves as intended under conforming implementations... union foo { char c; double d; };
77
4766
by: berns | last post by:
Hi All, A coworker and I have been debating the 'correct' expectation of evaluation for the phrase a = b = c. Two different versions of GCC ended up compiling this as b = c; a = b and the other ended up compiling it as a = c; b = c. (Both with no optimizations enabled). How did we notice you may ask? Well, in our case 'b' was a memory mapped register that only has a select number of writable bits. He claims it has been a 'C...
16
1364
by: Lauri Alanko | last post by:
The following code crashes on Solaris 10 when compiled without optimization: typedef struct Node Node; struct Node { int val; Node *next; };
20
2146
by: TimeHorse | last post by:
I would like to gauge interest in the following proposal: Problem: Assignment statements cannot be used as expressions. Performing a list of mutually exclusive checks that require data processing can cause excessive tabification. For example, consider the following python snipet...
9
3518
by: sturlamolden | last post by:
Python allows the binding behaviour to be defined for descriptors, using the __set__ and __get__ methods. I think it would be a major advantage if this could be generalized to any object, by allowing the assignment operator (=) to be overloaded. One particular use for this would be to implement "lazy evaluation". For example it would allow us to get rid of all the temporary arrays produced by NumPy. For example, consider the...
24
1638
by: boblatest | last post by:
Hello, I have an if-elif chain in which I'd like to match a string against several regular expressions. Also I'd like to use the match groups within the respective elif... block. The C-like idiom that I would like to use is this: if (match = my_re1.match(line): # use match elsif (match = my_re2.match(line)):
2
1505
by: donbock | last post by:
The paper Volatiles are Miscompiled, and What to Do about It by Eide and Regehr reports that mishandling of volatiles is a common category of compiler bugs. You should read it if you use volatiles for memory-mapped I/O or thread synchronization. Almost in passing they describe a common programmer error with volatiles: Inserting a "side-effecting operation" into the loop would also prevent the undesired transformation. Would inserting any...
0
9699
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9562
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10538
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10305
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9115
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6838
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5494
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5622
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2966
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.