[comp.lang.c] Assignment Ops and Side Effects

pjh@mccc.edu (Peter J. Holsberg) (04/04/91)

How does the standard describe the situation where, for example,
	x++ *= y;
is treated as if it were
	x++ = x * y;
and not
	x++ = x++ * y;


Pete
-- 
Prof. Peter J. Holsberg      Mercer County Community College
Voice: 609-586-4800          Engineering Technology, Computers and Math
UUCP:...!princeton!mccc!pjh  1200 Old Trenton Road, Trenton, NJ 08690
Internet: pjh@mccc.edu	     Trenton Computer Festival -- 4/20-21/91

gwyn@smoke.brl.mil (Doug Gwyn) (04/05/91)

In article <1991Apr3.173046.2367@mccc.edu> pjh@mccc.edu (Peter J. Holsberg) writes:
-How does the standard describe the situation where, for example,
-	x++ *= y;
-is treated as if it were
-	x++ = x * y;
-and not
-	x++ = x++ * y;

Correctly, of course.

bliss@sp64.csrd.uiuc.edu (Brian Bliss) (04/05/91)

> how does the standard describe the situation where, for example,
>	x++ *= y;
> is treated as if it were
>	x++ = x * y;
> and not
>	x++ = x++ * y;

The result of an increment or decrement operation is not a legal
lhs of an expression.

bb

P.S. an interesting tidbit I just found out:


if you're on a machine where sizeof (int) == 4, then

char ch;
sizeof (ch += 1) == 4
sizeof (ch++) == 1

apparrently operands of ++ and -- do not undergo integral promotion

torek@elf.ee.lbl.gov (Chris Torek) (04/05/91)

In article <1991Apr4.202314.961@csrd.uiuc.edu> bliss@sp64.csrd.uiuc.edu
(Brian Bliss) notes that on at least one system:
>	char ch;
>	sizeof (ch += 1) == 4
>	sizeof (ch++) == 1
>apparrently operands of ++ and -- do not undergo integral promotion

I am tempted to claim that this is a bug in the compiler in question,
but without the standard in front of me (I am reading news during
breakfast at home) I will go only as far as saying that, from a
reasonably abstract point of view,

	ch++

and

	ch += 1

should have the same type.  Gcc 1.39, for instance, makes them the same.
I doubt that gcc violates the standard in this regard, so either it is
undefined or implementation-defined as to exactly when promotion occurs
in assignment expressions, or else the compiler that gave you that
result is not conformant.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

twpierce@amherst.bitnet (Tim Pierce) (04/05/91)

In article <1991Apr3.173046.2367@mccc.edu>, pjh@mccc.edu (Peter J. Holsberg) writes:
> How does the standard describe the situation where, for example,
> 	x++ *= y;
> is treated as if it were
> 	x++ = x * y;
> and not
> 	x++ = x++ * y;

x++ is not an lvalue in any compiler that I know of.

-- 
____ Tim Pierce                     / 
\  / BITnet: twpierce@amherst       /   Forewarned is half an octopus.
 \/  Internet: twpierce@amherst.edu / 

   Never underestimate the bandwidth of a station wagon filled with tapes.

scs@adam.mit.edu (Steve Summit) (04/05/91)

In article <11805@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
>In article <1991Apr4.202314.961@csrd.uiuc.edu> bliss@sp64.csrd.uiuc.edu
>(Brian Bliss) notes that on at least one system:
>>	char ch;
>>	sizeof (ch += 1) == 4
>>	sizeof (ch++) == 1
>>apparrently operands of ++ and -- do not undergo integral promotion
>
>...from a reasonably abstract point of view,
>	ch++
>and
>	ch += 1
>should have the same type.  Gcc 1.39, for instance, makes them the same.

As does pcc.  

Note that the bug is not that "operands of ++ and -- do not
undergo integral promotion," but rather that the result of an
assignment operator apparently does.

X3.159 sections 3.3.2.4 and 3.3.3.1 say (of postfix and prefix,
respectively, increment and decrement operators) that we are to
"See the discussions of additive operators and compound
assignment for information on... types..."  Section 3.3.3.1
additionally asserts that "The expression ++E is equivalent to
(E+=1)."  Finally, section 3.3.16 says that "The type of an
assignment expression is the type of the left operand..."

Having just thought about this issue in a C tool I'm working on
(which happens to get the same answer as pcc and gcc in this
case), I can say that it's not terribly hard to get right.
Default promotions are (or ought to be) handled fairly
deliberately and explicitly inside a translater.  For each
operator, you ask yourself, "which promotions should I apply
here?"  For ++ and --, you don't apply any promotions, because
the operands are (and must remain) lvalues.  For += (and the
other op= operators), although promotions may come into play when
evaluating the right-hand side and performing the operation,
since the value is that of the left-hand side (that is, the
coerced value, after assignment), it's reasonably obvious that
the type should be, too.

For the compiler that thinks that sizeof(c += 1) is sizeof(int),
I wonder what it thinks about sizeof(c = 1) or sizeof(c = 1.0) ?

                                            Steve Summit
                                            scs@adam.mit.edu

ckp@grebyn.com (Checkpoint Technologies) (04/05/91)

In article <1991Apr4.202314.961@csrd.uiuc.edu> bliss@sp64.csrd.uiuc.edu (Brian Bliss) writes:
>P.S. an interesting tidbit I just found out:
>if you're on a machine where sizeof (int) == 4, then
>
>char ch;
>sizeof (ch += 1) == 4
>sizeof (ch++) == 1
>
>apparrently operands of ++ and -- do not undergo integral promotion

Is this really true?  Is it standard?

Does this means that if ch = 0xff (unsigned, 8 bit char), then i =
(++ch) assigns 0 to i (since the increment caused it to overflow)?
-- 
First comes the logo: C H E C K P O I N T  T E C H N O L O G I E S      / /  
                                                ckp@grebyn.com      \\ / /    
Then, the disclaimer:  All expressed opinions are, indeed, opinions. \  / o
Now for the witty part:    I'm pink, therefore, I'm spam!             \/

exspes@gdr.bath.ac.uk (P E Smee) (04/06/91)

In article <1991Apr3.173046.2367@mccc.edu> pjh@mccc.edu (Peter J. Holsberg) writes:
>How does the standard describe the situation where, for example,
>	x++ *= y;
>is treated as if it were
>	x++ = x * y;
>and not
>	x++ = x++ * y;

The quick answer is that x++ is (explicitly) not an lvalue, and so
cannot appear on the left-hand side of an assignment operator.

-- 
Paul Smee, Computing Service, University of Bristol, Bristol BS8 1UD, UK
 P.Smee@bristol.ac.uk - ..!uunet!ukc!bsmail!p.smee - Tel +44 272 303132

bliss@sp64.csrd.uiuc.edu (Brian Bliss) (04/06/91)

> For the compiler that thinks that sizeof(c += 1) is sizeof(int),
> I wonder what it thinks about sizeof(c = 1) or sizeof(c = 1.0) ?
(c is a char)

The compiler is Sun 4.0's cc, and indeed, it returns 1 for both cases.
So indeed it is the assignment that is responsible for coercing
the result back to char type.

bb

volpe@camelback.crd.ge.com (Christopher R Volpe) (04/08/91)

In article <1991Apr5.234636.22610@csrd.uiuc.edu>,
bliss@sp64.csrd.uiuc.edu (Brian Bliss) writes:
|>> For the compiler that thinks that sizeof(c += 1) is sizeof(int),
|>> I wonder what it thinks about sizeof(c = 1) or sizeof(c = 1.0) ?
|>(c is a char)
|>
|>The compiler is Sun 4.0's cc, and indeed, it returns 1 for both cases.
|>So indeed it is the assignment that is responsible for coercing
|>the result back to char type.
|>
|>bb

Could someone explain to me why sizeof(c=1) is 1 and not (typically) 4??
The result of the assignment operator is not an l-value, and thus undergoes
the integral promotions. The result of "c=1" in an expression context
should be promoted to int. For example, for an unprototyped function f,
f(c=1) assigns 1 to the character c, and then passes the INTEGER 1 to f.
Similarly, sizeof(c=1) should see that its operand is a non-lvalue value of
type char (the value is not evaluated) and should thus be promoted to int.
(For sizeof(c), c is an lvalue and does not undergo promotion since it is
an operand of sizeof. (Section 3.2.2.1 paragraph 2))
         
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

mcdaniel@adi.com (Tim McDaniel) (04/09/91)

In article <18324@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com
(Christopher R Volpe) writes:

   Could someone explain to me why sizeof(c=1) is 1 and not
   (typically) 4?? The result of the assignment operator is not an
   l-value, and thus undergoes the integral promotions.

Not true.  The default arithmetic conversions are never applied to the
operand of sizeof, whether lvalue or not; see section 3.3.3.4.  (It
doesn't mention any promotions there.  It's always careful to mention
promotions where they occur, as under "+".)

--
   "Of course he has a knife.  We all have knives.  It's 1183, and we're
   all barbarians."
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

gwyn@smoke.brl.mil (Doug Gwyn) (04/09/91)

In article <18324@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes:
>The result of "c=1" in an expression context should be promoted to int.

Not if it's the operand of sizeof; that would make sizeof rather useless.

fraser@mullauna.cs.mu.OZ.AU (Fraser Wilson) (04/09/91)

gwyn@smoke.brl.mil (Doug Gwyn) writes:

>In article <18324@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes:
>>The result of "c=1" in an expression context should be promoted to int.

>Not if it's the operand of sizeof; that would make sizeof rather useless.

No, it makes performing an assignment while doing a sizeof rather useless.
Requiring that an expression is promoted to int UNLESS it happens to be
in a sizeof seems unduly complicated.  IMHO.

Fraser.

volpe@camelback.crd.ge.com (Christopher R Volpe) (04/09/91)

In article <15765@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
|>In article <18324@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com
(Christopher R Volpe) writes:
|>>The result of "c=1" in an expression context should be promoted to int.
|>
|>Not if it's the operand of sizeof; that would make sizeof rather useless.

I don't think it would be useless at all. I could still do sizeof(c) and
get the size of a char if I wanted. Can you point me to a reference to
the Standard from which one can deduce that a NON-lvalue expression
of type char should NOT be promoted to int when it is the operand of
sizeof?

thanks,
Chris    
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

volpe@camelback.crd.ge.com (Christopher R Volpe) (04/10/91)

In article <MCDANIEL.91Apr8153946@dolphin.adi.com>, mcdaniel@adi.com
(Tim McDaniel) writes:
|>Not true.  The default arithmetic conversions are never applied to the
|>operand of sizeof, whether lvalue or not; see section 3.3.3.4.  (It
|>doesn't mention any promotions there.  It's always careful to mention
|>promotions where they occur, as under "+".)
|>

Yep, Mark Brader also pointed this out to me in email. Thank you both.
-Chris                 
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

gwyn@smoke.brl.mil (Doug Gwyn) (04/10/91)

In article <18355@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes:
>In article <15765@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
>|>In article <18324@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes:
>|>>The result of "c=1" in an expression context should be promoted to int.
>|>Not if it's the operand of sizeof; that would make sizeof rather useless.
>I don't think it would be useless at all. I could still do sizeof(c) and
>get the size of a char if I wanted. Can you point me to a reference to
>the Standard from which one can deduce that a NON-lvalue expression
>of type char should NOT be promoted to int when it is the operand of
>sizeof?

Yeah -- the whole damn standard.  It doesn't contain a specific
statement that says "Don't invent rules along the lines of Volpe";
instead it gives rules for properly determining what does happen:
3.3.16 Semantics:  The type of an assignment expression is the type of
the left operand...
3.3.3.4 Semantics:  The sizeof operator ... size is determined from
the type of the operand, which is not itself evaluated.
I see no room for for thinking that any sort of conversion should be
performed.

volpe@camelback.crd.ge.com (Christopher R Volpe) (04/10/91)

In article <15777@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
|>Yeah -- the whole damn standard.  It doesn't contain a specific
|>statement that says "Don't invent rules along the lines of Volpe";
|>instead it gives rules for properly determining what does happen:
|>3.3.16 Semantics:  The type of an assignment expression is the type of
|>the left operand...
|>3.3.3.4 Semantics:  The sizeof operator ... size is determined from
|>the type of the operand, which is not itself evaluated.
|>performed.
                    
3.2.1.1: A char ... may be used in an expression wherever an int or
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
unsigned int may be used. If an int can represent all values of the
original typ
^^^^^^^^^^^^^^^^^^^^^^^^^
e, the value is converted to an int.; otherwise, it is converted to an
unsigned int. These are called the integral promotions.

This appears to say that this conversion occurs in any expression
context, subject to explicit exceptions made elsewhere.

Footnote 27, which is not even technically part of the standard, clarifies
this by saying, in effect, that these promotions are done only where
explicitly indicated, not by default with possible exceptions. Obviously
someone thought that people might reach the same wrong conclusion as I
did, otherwise there would be no footnote. 

I didn't notice the footnote. Other people were able to point this 
out to me in a polite, civilized, non-hostile, and non-insulting manner.
With all due respect, perhaps you could learn to chill out a bit. Not all
of us were on the committee and not all of us have the whole document
memorized and not all of us are so perfect as to not be able to miss a
footnote. 

|>I see no room for for thinking that any sort of conversion should be
|>performed.

I think you mean, "I see no room for not having as thorough an 
understanding of the language as I have."

==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

mcdaniel@adi.com (Tim McDaniel) (04/10/91)

In article <18393@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com
(Christopher R Volpe) quotes:
> 
>    3.2.1.1: A char ... may be used in an expression wherever an int or
>                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    unsigned int may be used. If an int can represent all values of the
>    ^^^^^^^^^^^^^^^^^^^^^^^^^
>    original type, the value is converted to an int.; otherwise, it is
>    converted to an unsigned int. These are called the integral
>    promotions. 
> 
> This appears to say that this conversion occurs in any expression
> context, subject to explicit exceptions made elsewhere.

See the first paragraph of section 3.2, "Conversions":

   Several operators convert operand values from one type to another
   automatically.  This section specifies the result required from
   such an *implicit conversion* .... The list in 3.2.1.5 summarizes
   the conversions performed by most ordinary operators; it is
   supplemented as required by the discussion of each operator in 3.3.

Section 3.2.1.5, "Usual Arithmetic Conversions" (ditto):

   Many binary operators that expect operands of arithmetic type cause
   conversions and yield result types in a similar way....

--
   "Of course he has a knife.  We all have knives.  It's 1183, and we're
   all barbarians."
Tim McDaniel                 Applied Dynamics Int'l.; Ann Arbor, Michigan, USA
Internet: mcdaniel@adi.com                UUCP: {uunet,sharkey}!amara!mcdaniel

gwyn@smoke.brl.mil (Doug Gwyn) (04/13/91)

In article <18393@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes:
>3.2.1.1: A char ... may be used in an expression wherever an int or
>                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>This appears to say that this conversion occurs in any expression
>context, subject to explicit exceptions made elsewhere.

That's why you have to read the whole standard.  On the same page, at
the beginning of section 3.2, it explains when the conversions apply.

The result type for simple assignment is well specified.  There is
no license for applying any further conversion while evaluating
"sizeof(c=1)" EVEN ACCORDING TO YOUR ATTEMPT, unless you wish
"sizeof char_variable_name" to also be affected, which is clearly not
desirable.

>I didn't notice the footnote. Other people were able to point this 
>out to me in a polite, civilized, non-hostile, and non-insulting manner.
>With all due respect, perhaps you could learn to chill out a bit. Not all
>of us were on the committee and not all of us have the whole document
>memorized and not all of us are so perfect as to not be able to miss a
>footnote. 

The footnote is not part of the standard.  It was probably added in
response to some public review comment, maybe over the Redactor's
protests (several footnotes fell into that category), but was
considered technically inessential to a correct specification.

My response was civil, but if you choose to take it as an insult then
you're welcome to do so.

>|>I see no room for for thinking that any sort of conversion should be
>|>performed.
>I think you mean, "I see no room for not having as thorough an 
>understanding of the language as I have."

No, I meant what I said.  See my above analysis of the consequences of
carrying through what you had proposed as an interpretation.  I do
expect you to think through the full consequences of any such notion
when attempting to evaluate whether it makes sense or not.