[comp.sys.amiga.programmer] Compiler code

cs326ag@ux1.cso.uiuc.edu (Loren J. Rittle) (04/02/91)

In article <1991Apr2.002631.22799@mintaka.lcs.mit.edu> rjc@geech.gnu.ai.mit.edu (Ray Cromwell) writes:
>In article <mykes.1028@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>>>char buf[20];
>>>main()
>>>{
>>>  char *d=(char *)&buf;
>>>  const char *s="This is a test\n";
>>>  while(*s) { *d++=*s++; }
>>>}
>>>
>>>/* Test.s produced by gcc */
>>>
>>>#NO_APP
>>>gcc_compiled.:
>>>.text
>>>LC0:
>>>	.ascii "This is a test\12\0"
>>>	.even
>>>.globl _main
>>>_main:
>>>	lea _buf,a1
>>>	lea LC0,a0
>>>	tstb a0@
>>>	jeq L5
>>>L4:
>>>	moveb a0@+,a1@+
>>>	tstb a0@
>>>	jne L4
>>>L5:
>>>	rts
>>>.comm _buf,20
>><timing omitted>
>>
>>;/* test.s produced by me */		; (cycles)
>>	lea	text(pc),a0		; 8
>>	lea	buf(pc),a1		; 8
>BUG! This is not the same algorithm in the C code. Your code would move
>a NULL byte if a NULL string was passed when it should do nothing. I don't know
>why GCC doesn't generate PC relative instructions, but I think it has to do
>with UNIX and perhaps the scatter load/memory partitioning.
>
>>.loop	move.b	(a0)+,(a1)+		; 14*12
>>	bne.s	.loop			; 13*10+1*8
>>	rts				; 16
>>text	dc.b	'This is a test',10,0
>>buf	ds.b	20
>>
>>NO COMPARISON DUDE!  GCC makes 3 totally wasted instructions, and one of
>>them is inside your loop.  Try an example with nested loops and your
>>wasted clock cycles become a geometric progression.  Multiply the kind
>>of inefficiencies that GCC demonstrates here by EVERY loop and EVERY
>>function you have and your program is slower and bigger than it needs
>>to be.  To be specific, the GCC routine is 6 words longer and by the
>>time it is done executing, it will take 128 more clock cycles than
>>mine will (on a 68000).  Your routine takes 466 total clocks to execute,
>>mine takes 338.  I'm just your average 68000 assembler language programmer,
>>but I saved 28% CPU time.  You might also note that your 'C' source is
>>7 lines of code and so is my assembler code.
>
>  This code is compiled to run on a 68030 @ 50mhz, the difference in speed
>would be _very_ small. Hey, someone compile this on SAS/C with ALL
>optimizations on. You're just your average assembly language programmer
>yet you introduced a subtle bug into the program that will stomp on the
>first byte of a static global string by attempting to copy a null
>string. In a HUGE program this bug would be so subtle that it may
>take days to find out how a memory location is being sporatically
>trashed. Worse yet, a null string will have garbage following it that could
>span hundreds of bytes. 

As requested here is the SAS/C v5.10a generated code:


Using:	`lc -v -O -b0 test.c'
	`omd test.o'
<begin test.c>
// Same program with GNU coding style enforced...
char buf[20];

void main (void)
{
  char *d = (char *)&buf;
  char *s = "This is a test\n";  // Note I got rid of the const, as
				 // not only is it of questionable
				 // legality under ANSI C (YOU CHANGE THE
				 // VALUE OF s!), but also caused SAS/C
				 // to generate (good, but) strange
				 // (meaning LONG) code.

  while (*s)
    *d++=*s++;
}
<end test.c>

Lattice AMIGA 68000-68020 OBJ Module Disassembler V5.04.039
Copyright ) 1988, 1989 Lattice Inc.  All Rights Reserved.


Amiga Object File Loader V1.00
68000 Instruction Set

EXTERNAL DEFINITIONS

_main 0000-00    _buf 0000-02

SECTION 00 "test.c" 00000020 BYTES
       | 0000  48E7 0030                      MOVEM.L   A2-A3,-(A7)
       | 0004  47F9  0000 0000-02             LEA       02.00000000,A3
       | 000A  45F9  0000 0000-01             LEA       01.00000000,A2
       | 0010  6002                           BRA.B     0014
       | 0012  16DA                           MOVE.B    (A2)+,(A3)+
       | 0014  4A12                           TST.B     (A2)
       | 0016  66FA                           BNE.B     0012
       | 0018  4CDF 0C00                      MOVEM.L   (A7)+,A2-A3
       | 001C  4E75                           RTS

SECTION 01 " " 00000010 BYTES
0000 54 68 69 73 20 69 73 20 61 20 74 65 73 74 0A 00 This is a test..

SECTION 02 " " 00000014 BYTES

This compares quite nicely to GCC and the buggy asm code given above :-).

>or two of magnitude improvement. Matt's assembler is perfect proof. If
>Matt coded it in assembly and added some features it would blow away DevPac
>and probably beat ArgAsm.
I have to agree, Matt is a stud!

Loren J. Rittle
-- 
``NewTek stated that the Toaster  *would*  *not*  be made to directly support
  the Mac, at this point Sculley stormed out of the booth...'' --- A scene at
  the recent MacExpo.  Gee, you wouldn't think that an Apple Exec would be so
  worried about one little Amiga device... Loren J. Rittle  l-rittle@uiuc.edu

rjc@geech.gnu.ai.mit.edu (Ray Cromwell) (04/02/91)

In article <1991Apr2.100807.13471@ux1.cso.uiuc.edu> cs326ag@ux1.cso.uiuc.edu (Loren J. Rittle) writes:
>Using:	`lc -v -O -b0 test.c'
>	`omd test.o'
><begin test.c>
>// Same program with GNU coding style enforced...
>char buf[20];
>
>void main (void)
>{
>  char *d = (char *)&buf;
>  char *s = "This is a test\n";  // Note I got rid of the const, as
>				 // not only is it of questionable
>				 // legality under ANSI C (YOU CHANGE THE
>				 // VALUE OF s!), but also caused SAS/C
>				 // to generate (good, but) strange
>				 // (meaning LONG) code.
  You're right. I had a strange feeling that GCC would try to put
*s on the stack, so I made it const (static produces worse code).
I never really use const myself except to help generate compiler warnings
in some routines that I suspect of corrupting variables. Oddly enough, GCC
doesn't give a warning for the '*s++' which is a changing const. I now
find out that GCC produces the same code without the const. :-(

>
>  while (*s)
>    *d++=*s++;
>}
><end test.c>
>
>Lattice AMIGA 68000-68020 OBJ Module Disassembler V5.04.039
>Copyright ) 1988, 1989 Lattice Inc.  All Rights Reserved.
>
>
>Amiga Object File Loader V1.00
>68000 Instruction Set
>
>EXTERNAL DEFINITIONS
>
>_main 0000-00    _buf 0000-02
>
>SECTION 00 "test.c" 00000020 BYTES
>       | 0000  48E7 0030                      MOVEM.L   A2-A3,-(A7)
>       | 0004  47F9  0000 0000-02             LEA       02.00000000,A3
>       | 000A  45F9  0000 0000-01             LEA       01.00000000,A2
>       | 0010  6002                           BRA.B     0014
>       | 0012  16DA                           MOVE.B    (A2)+,(A3)+
>       | 0014  4A12                           TST.B     (A2)
>       | 0016  66FA                           BNE.B     0012
>       | 0018  4CDF 0C00                      MOVEM.L   (A7)+,A2-A3
>       | 001C  4E75                           RTS

 Hmm, is it standard practice of SAS/C to preserve a2-a5? I think it should
use a0/a1 as scratch registers. Try compiling it with a small data/code
option and it might make those lea's PC relative. BTW, I compiled
the code using DICE and DICE does a link a5,#0/unlk a5 which does nothing.
It should omit the frame pointer.

>SECTION 01 " " 00000010 BYTES
>0000 54 68 69 73 20 69 73 20 61 20 74 65 73 74 0A 00 This is a test..
>
>SECTION 02 " " 00000014 BYTES
>
>This compares quite nicely to GCC and the buggy asm code given above :-).
Hmm. Look's like I'll be purchasing SAS/C soon. :-)

>Loren J. Rittle
>-- 
>``NewTek stated that the Toaster  *would*  *not*  be made to directly support
>  the Mac, at this point Sculley stormed out of the booth...'' --- A scene at
>  the recent MacExpo.  Gee, you wouldn't think that an Apple Exec would be so
>  worried about one little Amiga device... Loren J. Rittle  l-rittle@uiuc.edu


--
/~\_______________________________________________________________________/~\
|n|   rjc@albert.ai.mit.edu   Amiga, the computer for the creative mind.  |n|
|~|                                .-. .-.                                |~|
|_|________________________________| |_| |________________________________|_|

mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) (04/03/91)

In article <1991Apr2.100807.13471@ux1.cso.uiuc.edu> cs326ag@ux1.cso.uiuc.edu (Loren J. Rittle) writes:

   In article <1991Apr2.002631.22799@mintaka.lcs.mit.edu> rjc@geech.gnu.ai.mit.edu (Ray Cromwell) writes:
   >In article <mykes.1028@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
   >>>char buf[20];
   >>>main()
   >>>{
   >>>  char *d=(char *)&buf;
   >>>  const char *s="This is a test\n";
   >>>  while(*s) { *d++=*s++; }
   >>>}
   void main (void)
   {
     char *d = (char *)&buf;
     char *s = "This is a test\n";  // Note I got rid of the const, as
				    // not only is it of questionable
				    // legality under ANSI C (YOU CHANGE THE
				    // VALUE OF s!), but also caused SAS/C
				    // to generate (good, but) strange
				    // (meaning LONG) code.

     while (*s)
       *d++=*s++;
   }

Actually, the code is perfectly valid. S is declared as a "pointer to
constant", which it is - the string isn't changed. To declare s as a
constant, its "char *const s". That would have been invalid.

	<mike

--
Here's a song about absolutely nothing.			Mike Meyer
It's not about me, not about anyone else,		mwm@pa.dec.com
Not about love, not about being young.			decwrl!mwm
Not about anything else, either.

mykes@amiga0.SF-Bay.ORG (Mike Schwartz) (04/03/91)

In article <1991Apr2.100807.13471@ux1.cso.uiuc.edu> cs326ag@ux1.cso.uiuc.edu (Loren J. Rittle) writes:
>In article <1991Apr2.002631.22799@mintaka.lcs.mit.edu> rjc@geech.gnu.ai.mit.edu (Ray Cromwell) writes:
>>In article <mykes.1028@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>>>>char buf[20];
>>>>main()
>>>>{
>>>>  char *d=(char *)&buf;
>>>>  const char *s="This is a test\n";
>>>>  while(*s) { *d++=*s++; }
>>>>}
>>>>
>>>>/* Test.s produced by gcc */
>>>>
>>>>#NO_APP
>>>>gcc_compiled.:
>>>>.text
>>>>LC0:
>>>>	.ascii "This is a test\12\0"
>>>>	.even
>>>>.globl _main
>>>>_main:
>>>>	lea _buf,a1
>>>>	lea LC0,a0
>>>>	tstb a0@
>>>>	jeq L5
>>>>L4:
>>>>	moveb a0@+,a1@+
>>>>	tstb a0@
>>>>	jne L4
>>>>L5:
>>>>	rts
>>>>.comm _buf,20
>>><timing omitted>
>>>
>>>;/* test.s produced by me */		; (cycles)
>>>	lea	text(pc),a0		; 8
>>>	lea	buf(pc),a1		; 8
>>BUG! This is not the same algorithm in the C code. Your code would move
>>a NULL byte if a NULL string was passed when it should do nothing. I don't know
>>why GCC doesn't generate PC relative instructions, but I think it has to do
>>with UNIX and perhaps the scatter load/memory partitioning.
>>
>>>.loop	move.b	(a0)+,(a1)+		; 14*12
>>>	bne.s	.loop			; 13*10+1*8
>>>	rts				; 16
>>>text	dc.b	'This is a test',10,0
>>>buf	ds.b	20
>>>
>>  This code is compiled to run on a 68030 @ 50mhz, the difference in speed
>>would be _very_ small. Hey, someone compile this on SAS/C with ALL
>>optimizations on. You're just your average assembly language programmer
>>yet you introduced a subtle bug into the program that will stomp on the
>>first byte of a static global string by attempting to copy a null
>>string. In a HUGE program this bug would be so subtle that it may
>>take days to find out how a memory location is being sporatically
>>trashed. Worse yet, a null string will have garbage following it that could
>>span hundreds of bytes. 
>

WRONG!!!

I have eyes and could see that you aren't using a NULL string, and NO string
was "passed" to anything.  Your compiler should have had the same sense that
I do.  This program doesn't copy some arbitrary string.  If you would have
wrote the following code, both I and your compiler would have generated a
different assembler language program:

main() {
	char	*s = "some string";
	char	buf[20];

	CopyString(s, buf);
}

CopyString(s,d)
char	*s,*d;
{
	while(*s) { *d++=*s++; }
}

>As requested here is the SAS/C v5.10a generated code:
>
>
>Using:	`lc -v -O -b0 test.c'
>	`omd test.o'
><begin test.c>
>// Same program with GNU coding style enforced...
>char buf[20];
>
>void main (void)
>{
>  char *d = (char *)&buf;
>  char *s = "This is a test\n";  // Note I got rid of the const, as
>				 // not only is it of questionable
>				 // legality under ANSI C (YOU CHANGE THE
>				 // VALUE OF s!), but also caused SAS/C
>				 // to generate (good, but) strange
>				 // (meaning LONG) code.
>


NOTE THE GOTCHA!!!!  My source would have assembled to the same
object code under any commercial assembler.


People who blindly use 'C' without understanding assembler language
are generating strange (meaning LONG) code in every program
they write.

--
********************************************************
* Appendix A of the Amiga Hardware Manual tells you    *
* everything you need to know to take full advantage   *
* of the power of the Amiga.  And it is only 10 pages! *
********************************************************

rjc@geech.gnu.ai.mit.edu (Ray Cromwell) (04/03/91)

In article <mykes.1274@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>In article <1991Apr2.100807.13471@ux1.cso.uiuc.edu> cs326ag@ux1.cso.uiuc.edu (Loren J. Rittle) writes:
>>In article <1991Apr2.002631.22799@mintaka.lcs.mit.edu> rjc@geech.gnu.ai.mit.edu (Ray Cromwell) writes:
>>>  This code is compiled to run on a 68030 @ 50mhz, the difference in speed
>>>would be _very_ small. Hey, someone compile this on SAS/C with ALL
>>>optimizations on. You're just your average assembly language programmer
>>>yet you introduced a subtle bug into the program that will stomp on the
>>>first byte of a static global string by attempting to copy a null
>>>string. In a HUGE program this bug would be so subtle that it may
>>>take days to find out how a memory location is being sporatically
>>>trashed. Worse yet, a null string will have garbage following it that could
>>>span hundreds of bytes. 
>>
>
>WRONG!!!
>
>I have eyes and could see that you aren't using a NULL string, and NO string
>was "passed" to anything.  Your compiler should have had the same sense that
>I do.  This program doesn't copy some arbitrary string.  If you would have
>wrote the following code, both I and your compiler would have generated a
>different assembler language program:

  Mike, you still don't get it. YOUR CODE used a different algorithm, but
our comparision was supposed to be based on comparisions of the same
algorithm. Your code was not the same as 'while (*s) *d++=*s++;'. Your code
was equivelent to 'do *d++=*s++; while(*s);' Again, someone with 
SAS/C compile the do/while version and I bet it will leave out the starting
'bra'. That's the reason I gave the 'boyer more in C vs brute force in
assembly' example because you weren't comparing the same algorithms.

>main() {
>	char	*s = "some string";
>	char	buf[20];
>
>	CopyString(s, buf);
>}
>
>CopyString(s,d)
>char	*s,*d;
>{
>	while(*s) { *d++=*s++; }
>}

  GCC and SAS/C would have 'inlined' these functions when optimizing
for speed. The point is, you did not translate my algorithm into proper
ASM code.

>>As requested here is the SAS/C v5.10a generated code:
>>
>>
>>Using:	`lc -v -O -b0 test.c'
>>	`omd test.o'
>><begin test.c>
>>// Same program with GNU coding style enforced...
>>char buf[20];
>>
>>void main (void)
>>{
>>  char *d = (char *)&buf;
>>  char *s = "This is a test\n";  // Note I got rid of the const, as
>>				 // not only is it of questionable
>>				 // legality under ANSI C (YOU CHANGE THE
>>				 // VALUE OF s!), but also caused SAS/C
>>				 // to generate (good, but) strange
>>				 // (meaning LONG) code.
>>
>
>
>NOTE THE GOTCHA!!!!  My source would have assembled to the same
>object code under any commercial assembler.

gcc_compiled.:
.text
LC0:
        .ascii "This is a test\12\0"
        .align 4
.global _main
        .proc 1
_main:
        !#PROLOGUE# 0
        save %sp,-80,%sp
        !#PROLOGUE# 1
        sethi %hi(_buf),%o2
        or %lo(_buf),%o2,%o2
        sethi %hi(LC0),%o1
        b L6
        or %o1,%lo(LC0),%o1
L4:
        ldsb [%o1],%o3
        stb %o3,[%o2]
        add %o1,1,%o1
        add %o2,1,%o2
L6:
        ldsb [%o1],%o0
        tst %o0
        bne L4
        nop
        ret
        restore
.global _buf
.common _buf,24,"bss"

  Here's the GOTCHA. This code became optimized RISC assembler
instructions on a SPARCStation. 

>People who blindly use 'C' without understanding assembler language
>are generating strange (meaning LONG) code in every program
>they write.

  Most professional developers who use C to do system level, low-level
code understand assembler and the hardware they are working on. If they
don't, it's likely that what they are coding doesn't need assembler.
Even Jeremy San prototypes his games in C before coding in assembler.
He also codes his tools in C (he said it himself on BIX).

>--
>********************************************************
>* Appendix A of the Amiga Hardware Manual tells you    *
>* everything you need to know to take full advantage   *
>* of the power of the Amiga.  And it is only 10 pages! *
>********************************************************


--
/~\_______________________________________________________________________/~\
|n|   rjc@albert.ai.mit.edu   Amiga, the computer for the creative mind.  |n|
|~|                                .-. .-.                                |~|
|_|________________________________| |_| |________________________________|_|

rhialto@cs.kun.nl (Olaf'Rhialto'Seibert) (04/05/91)

In article <1991Apr3.042457.3703@mintaka.lcs.mit.edu> someone writes:
>>CopyString(s,d)
>>char	*s,*d;
>>{
>>	while(*s) { *d++=*s++; }
>>}

Note that this function has an incorrect name. In C, a string is 0-terminated.
This does not copy the 0, so the copy is not a string.

This bug was already present in the very first program that started this
discussion, and I doubt the author was aware of this subtle but
dangerous bug.

--
Olaf 'Rhialto' Seibert                               rhialto@cs.kun.nl
How can you be so stupid if you're identical to me? -Robert Silverberg

jsmoller@jsmami.UUCP (Jesper Steen Moller) (04/07/91)

In article <2923@wn1.sci.kun.nl>, Olaf'Rhialto'Seibert writes:

> In article <1991Apr3.042457.3703@mintaka.lcs.mit.edu> someone writes:
> >>CopyString(s,d)
> >>char	*s,*d;
> >>{
> >>	while(*s) { *d++=*s++; }
> >>}
> 
> Note that this function has an incorrect name. In C, a string is 0-terminated.
> This does not copy the 0, so the copy is not a string.
> 
> This bug was already present in the very first program that started this
> discussion, and I doubt the author was aware of this subtle but
> dangerous bug.

Hmm, I think it was in order to fool the reader (and esp. the not C
minded...) - the produced code (commented by the poster cut it
out in cardboard, actually. The function is useful, actually,
if concatenating a lot of strings into one, and you don't want
the \0-pad overhead. 

char *stradd(d,s) /* All the good names are taken */
                  /* please note that dst, src is far more standard */
                  /* than src,dst */
{
    while(*s)
    {
        *d++=*s++;
        }
    return d; /* return updated destination pointer */
    }

The caller should use

d=stradd(d,s);
and finish off with a
*d="\0"; /* or d[0]=0; to be cryptic ;-) */

But on the other hand, I might be mistaken.

;) Jesper

> Olaf 'Rhialto' Seibert                               rhialto@cs.kun.nl
--                     __
Jesper Steen Moller   ///  VOICE: +45 31 62 46 45
Maglemosevej 52  __  ///  USENET: cbmehq!cbmdeo!jsmoller
DK-2920 Charl    \\\///  FIDONET: 2:231/84.45
Denmark           \XX/

urjlew@uncecs.edu (Rostyk Lewyckyj) (04/16/91)

In article <MWM.91Apr2120500@revelwood.pa.dec.com>, mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) writes:
> In article <1991Apr2.100807.13471@ux1.cso.uiuc.edu> cs326ag@ux1.cso.uiuc.edu (Loren J. Rittle) writes:
> 
>    In article <1991Apr2.002631.22799@mintaka.lcs.mit.edu> rjc@geech.gnu.ai.mit.edu (Ray Cromwell) writes:
>    >In article <mykes.1028@amiga0.SF-Bay.ORG> mykes@amiga0.SF-Bay.ORG (Mike Schwartz) writes:
>    >>>char buf[20];
>    >>>main()
>    >>>{
>    >>>  char *d=(char *)&buf;
>    >>>  const char *s="This is a test\n";
>    >>>  while(*s) { *d++=*s++; }
>    >>>}
>    void main (void)
>    {
>      char *d = (char *)&buf;
>      char *s = "This is a test\n";  // Note I got rid of the const, as
> 				    // not only is it of questionable
> 				    // legality under ANSI C (YOU CHANGE THE
> 				    // VALUE OF s!), but also caused SAS/C
> 				    // to generate (good, but) strange
> 				    // (meaning LONG) code.
> 
>      while (*s)
>        *d++=*s++;
>    }
> 
> Actually, the code is perfectly valid. S is declared as a "pointer to
> constant", which it is - the string isn't changed. To declare s as a
> constant, its "char *const s". That would have been invalid.
This probably belongs in comp.lang.c, but since C is the official
Amiga language, I post my comment here.
  
If a language causes this much controversy in just a variable/constant
declaration, and does not define any specific order for evaluations,
and does not have all the arithmetic operators (e.g. power), and 
does not have a computed go to (for branch tables) ....
How can it have such a zealous cult following of true believers?
How is it that an glorified assembler for the DEC PDP 11 has become
the language of choice for assembler hating CS students?

johnhlee@CS.Cornell.EDU (John H. Lee) (04/17/91)

In article <1991Apr16.001748.26530@uncecs.edu> urjlew@uncecs.edu (Rostyk Lewyckyj) writes:
[...]
>If a language causes this much controversy in just a variable/constant
>declaration, and does not define any specific order for evaluations,
>and does not have all the arithmetic operators (e.g. power), and 
>does not have a computed go to (for branch tables) ....
>How can it have such a zealous cult following of true believers?
>How is it that an glorified assembler for the DEC PDP 11 has become
>the language of choice for assembler hating CS students?

1)  The controversy is minor, and deals with a relatively new keyword in
the language ("const".)
2)  The C language specifies a *very* a clear order for evaluations.  May I
suggest you read the book by Kernighan and Ritchie, _The C Programming
Language_.
3)  The power arithmetic operator can be a relatively complex operation to
execute efficiently and best left in a library along with the trancendental
functions.  There is no lack of arithmetic operators that you suggest.
4)  In a structured language such as C, a multi-way branch statement (i.e.,
the 'switch' statement) is the proper method, not a computed goto (however,
the compiler is free to implement the switch statement as such.)
5)  I love assembler.  Assembler (for several different CPU's) was my first
language; BASIC was my second.  However C is my favorite.  The language of
choice for assembler-hating CS students is Pascal, not C.  The language of
choice to do actual work, however, is C.

-------------------------------------------------------------------------------
The DiskDoctor threatens the crew!  Next time on AmigaDos: The Next Generation.
	John Lee		Internet: johnhlee@cs.cornell.edu
The above opinions of those of the user, and not of this machine.

milamber@caen.engin.umich.edu (Daryl Cantrell) (04/18/91)

In article <1991Apr16.183638.12808@cs.cornell.edu> johnhlee@cs.cornell.edu (John H. Lee) writes:
>In article <1991Apr16.001748.26530@uncecs.edu> urjlew@uncecs.edu (Rostyk Lewyckyj) writes:
>[...]
>>If a language causes this much controversy in just a variable/constant
>>declaration, and does not define any specific order for evaluations,
>>and does not have all the arithmetic operators (e.g. power), and 
>>does not have a computed go to (for branch tables) ....
>>How can it have such a zealous cult following of true believers?
>>How is it that an glorified assembler for the DEC PDP 11 has become
>>the language of choice for assembler hating CS students?
[...]
>2)  The C language specifies a *very* a clear order for evaluations.  May I
>suggest you read the book by Kernighan and Ritchie, _The C Programming
>Language_.
[...]

  I don't think you take his meaning... If you have an expression like

  a * b + c * d

C defines the order of operations with regard to the operators.  That is,
the multiplications will be performed before the addition.  However, there
is no way to know whether a * b or c * d will be evaluated first.  Simi-
larly, it is not defined whether a or b will be evaluated first in the
multiplication.  The only exceptions are the && and || operators, where
left operand can short circuit the right.

  Personally, I would find such a definition about as useful as computed
gotos... (Not at all)

  To the original (?) poster: What difference does it make how it happen-
ned?  I use C because it's fast, powerful, and intuitive.  Every program-
mer has their own reasons for their choice of language.  How is it that
which language I use is so important to you?  If programmers everywhere
are using it (which they are), there must be some reason, eh?


--
+---------------------------------------+----------------------------+
|   // Daryl S. Cantrell                |   These opinions are       |
| |\\\ milamber@caen.engin.umich.edu    |    shared by all of    //  |
| |//  Evolution's over.  We won.       |        Humanity.     \X/   |
+---------------------------------------+----------------------------+

mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) (04/18/91)

In article <1991Apr18.122054.13695@athena.mit.edu> amgreene@athena.mit.edu (Andrew Marc Greene) writes:
   Oh, but it *is* useful!  What is the value of the following code
   fragment?

     int n = 4;

     (++n) * (--n);

   If the first operand to * is treated first, the answer is 20.  If the
   second operand to * is treated first, the answer is 12.  

Yup, you can tie the compiler writers hands some, and make things like
that have a meaning. I'd rather not tie the compiler writers hands,
and let them generate the fastest code for their machine. A good
compiler that sees what you wrote would generate no code whatsoever -
after all, you don't change n, and you don't assign the value to
anything.  Even if the value wasn't dead, a good compiler could
generate a simple multiply without changing the value of n, and still
be correct.  A better one would generate no code, and still be
correct.

	<mike
--
Can't buy happiness no matter what you do		Mike Meyer
Can't get to heaven on roller skates			mwm@pa.dec.com
Can't take a taxicab to Timbuktu			decwrl!mwm
Life is hard.

amgreene@athena.mit.edu (Andrew Marc Greene) (04/18/91)

In article <1991Apr17.180342.25312@engin.umich.edu> milamber@caen.engin.umich.edu (Daryl Cantrell) writes:
>  I don't think you take his meaning... If you have an expression like
>
>  a * b + c * d
>
>C defines the order of operations with regard to the operators.  That is,
>the multiplications will be performed before the addition.  However, there
>is no way to know whether a * b or c * d will be evaluated first.  Simi-
>larly, it is not defined whether a or b will be evaluated first in the
>multiplication.  The only exceptions are the && and || operators, where
>left operand can short circuit the right.
>
>  Personally, I would find such a definition about as useful as computed
>gotos... (Not at all)

Oh, but it *is* useful!  What is the value of the following code
fragment?

  int n = 4;

  (++n) * (--n);

If the first operand to * is treated first, the answer is 20.  If the
second operand to * is treated first, the answer is 12.  

-- Andrew <amgreene@mit.edu> | .sigs are for people with bandwidth to burn

david@kessner.denver.co.us (David Kessner) (04/19/91)

In article <1991Apr18.122054.13695@athena.mit.edu> amgreene@athena.mit.edu (Andrew Marc Greene) writes:
>Oh, but it *is* useful!  What is the value of the following code
>fragment?
>
>  int n = 4;
>
>  (++n) * (--n);
>
>If the first operand to * is treated first, the answer is 20.  If the
>second operand to * is treated first, the answer is 12.  
>
>-- Andrew <amgreene@mit.edu> | .sigs are for people with bandwidth to burn

Humph.  The answer is 16.

The pre-operators (--n ++n) mean "evaluate these expressions before anything
else".  So the above statement is the same as:

	n=n+1;
	n=n-1;
	?? = n * n;

Try it.

-- 
David Kessner - david@kessner.denver.co.us            | do {
1135 Fairfax, Denver CO  80220  (303) 377-1801 (p.m.) |    . . .
If you cant flame MS-DOS, who can you flame?          |    } while( jones);

milamber@caen.engin.umich.edu (Daryl Cantrell) (04/19/91)

In article <1991Apr18.212939.3461@kessner.denver.co.us> david@kessner.denver.co.us (David Kessner) writes:
>In article <1991Apr18.122054.13695@athena.mit.edu> amgreene@athena.mit.edu (Andrew Marc Greene) writes:
>>Oh, but it *is* useful!  What is the value of the following code
>>fragment?
>>
>>  int n = 4;
>>
>>  (++n) * (--n);
>>
>>If the first operand to * is treated first, the answer is 20.  If the
>>second operand to * is treated first, the answer is 12.  
>>
>>-- Andrew <amgreene@mit.edu> | .sigs are for people with bandwidth to burn

  And such a useful expression, too.  Really.

>Humph.  The answer is 16.
>
>The pre-operators (--n ++n) mean "evaluate these expressions before anything
>else".  So the above statement is the same as:
>
>	n=n+1;
>	n=n-1;
>	?? = n * n;
>
>Try it.
>
>-- 
>David Kessner - david@kessner.denver.co.us            | do {
>1135 Fairfax, Denver CO  80220  (303) 377-1801 (p.m.) |    . . .
>If you cant flame MS-DOS, who can you flame?          |    } while( jones);

  Nope.  ++ and -- are unary operators of the highest precedence.  The only
difference between ++x and x++ is the value they assume, the order of eval-
uation follows standard C precedence..


--
+---------------------------------------+----------------------------+
|   // Daryl S. Cantrell                |   These opinions are       |
| |\\\ milamber@caen.engin.umich.edu    |    shared by all of    //  |
| |//  Evolution's over.  We won.       |        Humanity.     \X/   |
+---------------------------------------+----------------------------+

mr3@ukc.ac.uk (M.Rizzo) (04/20/91)

In article <1991Apr18.122054.13695@athena.mit.edu> amgreene@athena.mit.edu (Andrew Marc Greene) writes:
>In article <1991Apr17.180342.25312@engin.umich.edu> milamber@caen.engin.umich.edu (Daryl Cantrell) writes:

>> ...However, there
>> is no way to know whether a * b or c * d will be evaluated first ...
>>
>> ... Personally, I would find such a definition about as useful as computed
>>gotos... (Not at all)
>
>Oh, but it *is* useful!  What is the value of the following code
>fragment?
>
>  int n = 4;
>
>  (++n) * (--n);
>
>If the first operand to * is treated first, the answer is 20.  If the
>second operand to * is treated first, the answer is 12.  

What you show in the above example is true - but I can't see why you
consider it to be useful.

In fact the example you give is highly redundant as you don't really
want to change the value of n, yet you are incrementing and decrementing
it (not very useful). I know its only meant to be an example
but how about

	(n+1) * n      to give 20
  and   (n-1) * n      to give 12           :-)

The point that I am trying to make is that using the increment/decrement
operators as mentioned above is very ugly and there is always a neater
way of expressing one's intentions.

Michael Rizzo

comeau@ditka.Chicago.COM (Greg Comeau) (04/22/91)

In article <1991Apr17.180342.25312@engin.umich.edu> milamber@caen.engin.umich.edu (Daryl Cantrell) writes:
>In article <1991Apr16.183638.12808@cs.cornell.edu> johnhlee@cs.cornell.edu (John H. Lee) writes:
>>In article <1991Apr16.001748.26530@uncecs.edu> urjlew@uncecs.edu (Rostyk Lewyckyj) writes:
>>2)  The C language specifies a *very* a clear order for evaluations.  May I
>>suggest you read the book by Kernighan and Ritchie, _The C Programming
>>Language_.
>  I don't think you take his meaning... If you have an expression like
>  a * b + c * d
>C defines the order of operations with regard to the operators.

>  To the original (?) poster: What difference does it make how it happen-
>ned?

it makes a difference how it happens because as you say, c*d could
happen before a*b, as well as a few other things (and this is a simple)
case.

Bottom line is that the order *can* effect the resulting value of the
expression.

- Greg
-- 
	 Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418
                            Producers of Comeau C++
          Here:attmail.com!csanta!comeau / BIX:comeau / CIS:72331,3421
                     Voice:718-945-0009 / Fax:718-441-2310

GHGAQZ4@cc1.kuleuven.ac.be (04/22/91)

>  Nope.  ++ and -- are unary operators of the highest precedence.  The only
>difference between ++x and x++ is the value they assume, the order of eval-
>uation follows standard C precedence..

I think you are wrong. Look at the following results :
I have tried this with our mainframe compiler :
   int n=4;

   (n--)*(n++)   ->   12
   (n++)*(n--)   ->   20
   (--n)*(++n)   ->   16
   (++n)*(--n)   ->   16
   (--n)*(n++)   ->   12
   (++n)*(n--)   ->   20
   (n--)*(++n)   ->   16
   (n++)*(--n)   ->   16

          Jorrit Tyberghein

cs450a03@uc780.umd.edu (04/23/91)

(sorry about the mangled subject line.  My newsreader does that for
you automatically.)

Jorrit Tyberghein   >
Someone Else        >>

>> Nope.  ++ and -- are unary operators of the highest precedence.
>>The only difference between ++x and x++ is the value they assume,
>>the order of evaluation follows standard C precedence..

>I think you are wrong. Look at the following results :
>I have tried this with our mainframe compiler :

[examples like  (n--)*(n++)  deleted]

If you have C change something twice, without specifying what order to
change them in, then C will usually pick the order arbitrarily.

This means, for instance, that

    int n=4;
    printf("%d\n", (n--)*(n++));

could print 12, 16, or 20, depending on the compiler.

Also, it is possible that the idiom (n--)*(n++) will evaluate in a
different order at different places in the _same_ program, especially
if the program is compiled with optimization turned on.

Raul Rockwell

(I'd have thought more people would have pounced on this thread
earlier....)

milamber@caen.engin.umich.edu (Daryl Cantrell) (04/23/91)

In article <91112.093750GHGAQZ4@cc1.kuleuven.ac.be> GHGAQZ4@cc1.kuleuven.ac.be writes:
>>  Nope.  ++ and -- are unary operators of the highest precedence.  The only
>>difference between ++x and x++ is the value they assume, the order of eval-
>>uation follows standard C precedence..
>
>I think you are wrong. Look at the following results :
>I have tried this with our mainframe compiler :
>   int n=4;
>
>   (n--)*(n++)   ->   12
>   (n++)*(n--)   ->   20
>   (--n)*(++n)   ->   16
>   (++n)*(--n)   ->   16
>   (--n)*(n++)   ->   12
>   (++n)*(n--)   ->   20
>   (n--)*(++n)   ->   16
>   (n++)*(--n)   ->   16
>
>          Jorrit Tyberghein

  You missed my point.  I was saying that ++ and -- are unary operators which
will be evaluated before the multiplication.  You've pointed out the argument
this stems from, which is that there's no way to know which side of the mult-
iplication is evaluated (You're compiler does the left first..).


--
+---------------------------------------+----------------------------+
|   // Daryl S. Cantrell                |   These opinions are       |
| |\\\ milamber@caen.engin.umich.edu    |    shared by all of    //  |
| |//  Evolution's over.  We won.       |        Humanity.     \X/   |
+---------------------------------------+----------------------------+

comeau@ditka.Chicago.COM (Greg Comeau) (04/23/91)

In article <1991Apr18.212939.3461@kessner.denver.co.us> david@kessner.denver.co.us (David Kessner) writes:
>In article <1991Apr18.122054.13695@athena.mit.edu> amgreene@athena.mit.edu (Andrew Marc Greene) writes:
>>  int n = 4; (++n) * (--n);
>Humph.  The answer is 16.
>The pre-operators (--n ++n) mean "evaluate these expressions before anything
>else".  So the above statement is the same as:
>	n=n+1; 	n=n-1; 	?? = n * n;
>Try it.

Not quite.  First, C has some liberties in it's evaluation of some
expressions.  Second, exactly when side-effects take place in a given
expression is undefined.

Bottom line: 16 *might* work for your compiler, but needn't.

- Greg
-- 
	 Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418
                            Producers of Comeau C++
          Here:attmail.com!csanta!comeau / BIX:comeau / CIS:72331,3421
                     Voice:718-945-0009 / Fax:718-441-2310

GHGAQZ4@cc1.kuleuven.ac.be (04/23/91)

>>
>>I think you are wrong. Look at the following results :
>>I have tried this with our mainframe compiler :
>>   int n=4;
>>
>>   (n--)*(n++)   ->   12
>>   (n++)*(n--)   ->   20
>>   (--n)*(++n)   ->   16
>>   (++n)*(--n)   ->   16
>>   (--n)*(n++)   ->   12
>>   (++n)*(n--)   ->   20
>>   (n--)*(++n)   ->   16
>>   (n++)*(--n)   ->   16
>>
>>          Jorrit Tyberghein
>
>  You missed my point.  I was saying that ++ and -- are unary operators which
>will be evaluated before the multiplication.  You've pointed out the argument
>this stems from, which is that there's no way to know which side of the mult-
>iplication is evaluated (You're compiler does the left first..).

There is something I don't understand about this. You say that the compiler
evaluates left first. But how do you interprete (--n)*(++n) ? If the compiler
would go from left to right he should first compute --n (or n=n-1). This is
the left side of the expression. And after that the compiler would evaluate
(++n) which is the right side of the expression. Obviously I'm thinking wrong
because this would give 12 instead of 16. What really happens here is that
   (--n)*(++n) gets translated to :
   --n
   ++n
   (n)*(n)   (or something equivalent)
I've looked at the compiled code and this is indeed what is evaluated.
But why does (n++)*(n--) not evaluate to the equivalent :
   (n)*(n)
   n++
   n--
I thought that ALL --x or ++x operators where to be evaluated BEFORE the
evaluation of the total expression happens (and this is presumably also
what happens) and that ALL x++ or x-- operators where to be evaluated
AFTER the evaluation of the total expression (and this is presumably
not true). This would seem more logical to me.

By the way. Lattice C generates exactly the same results.


                          Jorrit Tyberghein

nfs1675@dsacg3.dsac.dla.mil (Michael S Figg) (04/23/91)

In article <91112.093750GHGAQZ4@cc1.kuleuven.ac.be>, GHGAQZ4@cc1.kuleuven.ac.be writes:
> >  Nope.  ++ and -- are unary operators of the highest precedence.  The only
> >difference between ++x and x++ is the value they assume, the order of eval-
> >uation follows standard C precedence..
> 
> I think you are wrong. Look at the following results :
> I have tried this with our mainframe compiler :
>    int n=4;
> 
>    (n--)*(n++)   ->   12
>    (n++)*(n--)   ->   20
>    (--n)*(++n)   ->   16
>    (++n)*(--n)   ->   16
>    (--n)*(n++)   ->   12
>    (++n)*(n--)   ->   20
>    (n--)*(++n)   ->   16
>    (n++)*(--n)   ->   16
> 
>           Jorrit Tyberghein


I've tried this on 3 different machines and only proved that this is poor
(real poor) coding practice. Including the above test, 6 out of the 
8 permutations had three different answers. Results are as follow:

		    Jorrit        Gould 9050       ATT 3B2      PC (MSC 6.0)
    (n--)*(n++)   ->   12            20              12              16
    (n++)*(n--)   ->   20            12              20              16
    (--n)*(++n)   ->   16            16              12              16
    (++n)*(--n)   ->   16            16              20              16
    (--n)*(n++)   ->   12            16               9               9
    (++n)*(n--)   ->   20            16              25              25
    (n--)*(++n)   ->   16            20              16              25
    (n++)*(--n)   ->   16            12              16               9

Since I'm not at home, I haven't had the chance to try this on the Amiga 
(SAS/C 5.1), but it would probably be as unpredictable as the other 4 
machines.

---Mike,

-- 
 --------       o       A herd of bagels      | Michael Figg  DSAC-FSD
 |      |  --  oo o o   escaping from a deli. | DLA Systems Automation Center
 |      |  -- ooo oo    Looking for Lox in    | Cols, Ohio mfigg@dsac.dla.mil
 --------      o o      all the wrong places  | CIS: 73777,360    

milamber@caen.engin.umich.edu (Daryl Cantrell) (04/23/91)

In article <91113.092907GHGAQZ4@cc1.kuleuven.ac.be> <GHGAQZ4@cc1.kuleuven.ac.be> writes:
>>>
>>>I think you are wrong. Look at the following results :
>>>I have tried this with our mainframe compiler :
>>>   int n=4;
>>>
>>>   (n--)*(n++)   ->   12
>>>[...]
>>>   (n++)*(--n)   ->   16
>>>
>>>          Jorrit Tyberghein
>>
>>  You missed my point.  I was saying that ++ and -- are unary operators which
>>will be evaluated before the multiplication.  You've pointed out the argument
>>this stems from, which is that there's no way to know which side of the mult-
>>iplication is evaluated (You're compiler does the left first..).
>
>There is something I don't understand about this. You say that the compiler
>evaluates left first. But how do you interprete (--n)*(++n) ? If the compiler
>would go from left to right he should first compute --n (or n=n-1). This is
>the left side of the expression. And after that the compiler would evaluate
>(++n) which is the right side of the expression. Obviously I'm thinking wrong
>because this would give 12 instead of 16. What really happens here is that
>   (--n)*(++n) gets translated to :
>   --n
>   ++n
>   (n)*(n)   (or something equivalent)
>I've looked at the compiled code and this is indeed what is evaluated.
>But why does (n++)*(n--) not evaluate to the equivalent :
>   (n)*(n)
>   n++
>   n--
>I thought that ALL --x or ++x operators where to be evaluated BEFORE the
>evaluation of the total expression happens (and this is presumably also
>what happens) and that ALL x++ or x-- operators where to be evaluated
>AFTER the evaluation of the total expression (and this is presumably
>not true). This would seem more logical to me.
>
>By the way. Lattice C generates exactly the same results.
>
>
>                          Jorrit Tyberghein

  This is the "problem" with C (if such you consider it).  "Left to right"
refers to the order OPERATIONS are evaluated.  There is NO defined order
for evaluating the OPERANDS.  For instance, if you take "a + b + c", C
guarantees that a + b will be computed, and then added to c.  However,
there is no guarantee as to whether a or b will be evaluated first.
  ++ and -- are unary operators, which are evaluated with other operators
of the same precedence (unary -, for instance).  the difference between
++x and x++ is whether x is incremented before or after evaluating x.  So
if you had:

int main()
   {
   int x = 4;

   printf("%d",x * 3 + ++x);
   }

the answer I get (Lattice 5.1) is 17, not 20 as you suggest.

--
+---------------------------------------+----------------------------+
|   // Daryl S. Cantrell                |   These opinions are       |
| |\\\ milamber@caen.engin.umich.edu    |    shared by all of    //  |
| |//  Evolution's over.  We won.       |        Humanity.     \X/   |
+---------------------------------------+----------------------------+

dillon@overload.Berkeley.CA.US (Matthew Dillon) (04/24/91)

In article <91112.093750GHGAQZ4@cc1.kuleuven.ac.be> GHGAQZ4@cc1.kuleuven.ac.be writes:
>>  Nope.  ++ and -- are unary operators of the highest precedence.  The only
>>difference between ++x and x++ is the value they assume, the order of eval-
>>uation follows standard C precedence..
>
>I think you are wrong. Look at the following results :
>I have tried this with our mainframe compiler :
>   int n=4;
>
>   (n--)*(n++)   ->   12
>   (n++)*(n--)   ->   20
>   (--n)*(++n)   ->   16
>   (++n)*(--n)   ->   16
>   (--n)*(n++)   ->   12
>   (++n)*(n--)   ->   20
>   (n--)*(++n)   ->   16
>   (n++)*(--n)   ->   16
>
>	   Jorrit Tyberghein

    Obviously the compiler is going to do it a certain way, but that
    represents only the particular implementation of the compiler used. If
    you have an expression:

	exp1 * exp2

    There is NO GUARENTEE on the order of evaluation... exp1 before exp2 or
    exp2 before exp1, no matter *what* exp1 and exp2 contains.	Period.
    Never rely on side effects a particular compiler gives you.  If you
    have an expression:

	exp1 + exp2 * exp3

    There is still NO GUARENTEE which expression will be evaluated first..
    it could be exp1, exp2, OR exp3.  The ONLY guarentee is that exp2 will
    be multipled to exp3 and then added to exp1 ... exp1 might be evaluated
    before exp2 & exp3, or after, etc, etc, etc....

    The ONLY three C operators that guarentee evaluation order are &&, ||,
    and the comma as an operator (when not used in a subroutine call, where
    it doesn't act as the comma operator).

    ++ and -- are NOT guarenteed to execute their operations before or
    after the entire expression is computed, they could be localized to
    the sub expression, globalized, or the result otherwise evaluated at
    ANY TIME and assigned back to the variable at any time after all
    within the context of the expression.  Something like:

	++a + ++a

    If a is 1, the result can be 2 + 2 or 2 + 3 or 3 + 2 and at the end 'a'
    can be either 3 or 4 depending on how the compiler was designed. DO NOT
    DEPEND ON ANY PARTICULAR SIDE EFFECT WITH ++ or -- ACTING ON THE SAME
    VARIABLE MORE THAN ONCE IN ANY EXPRESSION, EVER, OR YOUR CODE WILL BE
    UNPORTABLE EVEN ACROSS REVISIONS OF THE SAME COMPILER!

					    -Matt

--

    Matthew Dillon	    dillon@Overload.Berkeley.CA.US
    891 Regal Rd.	    uunet.uu.net!overload!dillon
    Berkeley, Ca. 94708
    USA

dillon@overload.Berkeley.CA.US (Matthew Dillon) (04/24/91)

In article <1991Apr23.020319.7216@engin.umich.edu> milamber@caen.engin.umich.edu (Daryl Cantrell) writes:
>In article <91112.093750GHGAQZ4@cc1.kuleuven.ac.be> GHGAQZ4@cc1.kuleuven.ac.be writes:
>>>  Nope.  ++ and -- are unary operators of the highest precedence.  The only
>>>..
>
>  You missed my point.  I was saying that ++ and -- are unary operators which
>will be evaluated before the multiplication.  You've pointed out the argument
>this stems from, which is that there's no way to know which side of the mult-
>iplication is evaluated (You're compiler does the left first..).

    evaluation order != operator execution order.  Here is an example:

	b = a++ + a++;

    (one possible method the C compiler might generate)

    (1) calculate t1 = a + 1
    (2) calculate t2 = a + 1
    (3) calculate t3 = t1 + t2
    (4) calculate b = t3
    (5) calculate a = t1
    (6) calculate a = t2

    Here is another example:

	d = a * b + c;

    (one possible method the C compiler might generate)

    (1) calculate t1 = c
    (2) calculate t2 = b
    (3) calculate t3 = a
    (4) calculate t4 = t2 * t3
    (5) calculate t5 = t4 + t1
    (6) calculate d = t5

    As you can see, operator precedence and execution of operators does in
    NO WAY match the evaluation of expressions that those operators act on.

    In otherwords, side effects such as ++a and a++ will be calculated
    properly if used singly in an expression, but NO guarentees are given
    on how they are calculated if used multiply in an expression.  Even
    without optimization turned on.

						-Matt

>--
>+---------------------------------------+----------------------------+
>|   // Daryl S. Cantrell		 |   These opinions are       |
>| |\\\ milamber@caen.engin.umich.edu	 |    shared by all of	  //  |
>| |//	Evolution's over.  We won.       |        Humanity.     \X/   |
>+---------------------------------------+----------------------------+

--

    Matthew Dillon	    dillon@Overload.Berkeley.CA.US
    891 Regal Rd.	    uunet.uu.net!overload!dillon
    Berkeley, Ca. 94708
    USA

ccplumb@rose.waterloo.edu (Colin Plumb) (04/24/91)

ANSI C standard, section 3.3 Expressions:
"Between the previous and next sequence point an object shall have its
stored value modifiedat most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the
value to be stored.31"

"31.  This paragraph renders undefined statement expressions such as
	i = ++i + 1;
while allowing
	i = i + 1;"

I'm not going to type in the verbiage about sequence points, but they
are barriers requiring the completion of side effects before them
before access to the variables after.  They occur in a number of
obvious places (between statements, between the left and right sides of
&& || and comma operators, between the evaluation of the arguments and
procedure in a function call, and the call itself, and a few other
places.  In particular, there is no sequence point between the various
arguments to a function, nor is there one between the value-returning
and incrementing features of ++i and i++.

(++i) is equivalent to (i++ + 1)
(i++) is equivalent to (++i - 1)

By both tradition and the ANSI standard, modifying a variable twice in one
expression is undefined.  Don't do it.
-- 
	-Colin

mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) (04/25/91)

In article <dillon.6879@overload.Berkeley.CA.US> dillon@overload.Berkeley.CA.US (Matthew Dillon) writes:
       The ONLY three C operators that guarentee evaluation order are &&, ||,
       and the comma as an operator (when not used in a subroutine call, where
       it doesn't act as the comma operator).

Don't forget ?:. It is (they are?) a trinary operator, and guarantees
that the leftmost operand is evaluated first, then only one of the
other two is evaluated.

       ++a + ++a

       If a is 1, the result can be 2 + 2 or 2 + 3 or 3 + 2 and at the end 'a'
       can be either 3 or 4 depending on how the compiler was designed.
 
Actually, ANSI says the result is "undefined". Normally, you'll get
one of the things you mentioned or 3 + 3, but there are oddball
compilers out there that completely unexpected things.

The bottom line is still the same - you don't want to do this kind of thing.

	<mike

--
Tried to amend my carnivorous habits			Mike Meyer
Made it nearly seventy days				mwm@pa.dec.com
Loosing weight without speed				decwrl!mwm
Eatin' sunflower seeds

jsmoller@jsmami.UUCP (Jesper Steen Moller) (04/26/91)

In article <dillon.6879@overload.Berkeley.CA.US> dillon@overload.Berkeley.CA.US (Matthew Dillon) writes:
> 
> In article <91112.093750GHGAQZ4@cc1.kuleuven.ac.be> GHGAQZ4@cc1.kuleuven.ac.be writes:
> >>  Nope.  ++ and -- are unary operators of the highest precedence.  The only
> >>difference between ++x and x++ is the value they assume, the order of eval-
> >>uation follows standard C precedence..
> >
> >I think you are wrong. Look at the following results :
> >I have tried this with our mainframe compiler :
> >   int n=4;
> >
> >   (n--)*(n++)   ->   12
> >   (n++)*(n--)   ->   20
> >   (--n)*(++n)   ->   16
> >   (++n)*(--n)   ->   16
> >   (--n)*(n++)   ->   12
> >   (++n)*(n--)   ->   20
> >   (n--)*(++n)   ->   16
> >   (n++)*(--n)   ->   16
> >
> >	   Jorrit Tyberghein
> 
>     Obviously the compiler is going to do it a certain way, but that
>     represents only the particular implementation of the compiler used. If
>     you have an expression:
> 
> 	exp1 * exp2
> 
>     There is NO GUARENTEE on the order of evaluation... exp1 before exp2 or
>     exp2 before exp1, no matter *what* exp1 and exp2 contains.	Period.

Aha! A friend of mine asked if you could rely on the following:
---- FICTIVE CODE START ----

int func1(void);
int func2(void);

int result;

    result=func1()+func2();
---- FICTIVE CODE END ----

Question: Can't you rely on func1() being called before func2()???
Really not?

> 	++a + ++a
> 
>     If a is 1, the result can be 2 + 2 or 2 + 3 or 3 + 2 and at the end 'a'
>     can be either 3 or 4 depending on how the compiler was designed. DO NOT
>     DEPEND ON ANY PARTICULAR SIDE EFFECT WITH ++ or -- ACTING ON THE SAME
>     VARIABLE MORE THAN ONCE IN ANY EXPRESSION, EVER, OR YOUR CODE WILL BE
>     UNPORTABLE EVEN ACROSS REVISIONS OF THE SAME COMPILER!

H*ll to debug, anyway... min() and max() rules!!!

Oh, by the way: func(a++)

Is "a" increased before or after the function call. I think I once read in
K&R that it was undefined, but I might be mistaken.


> 					    -Matt

Greets, Jesper

--                     __
Jesper Steen Moller   ///  VOICE: +45 31 62 46 45
Maglemosevej 52  __  ///  USENET: cbmehq!cbmdeo!jsmami!jsmoller
DK-2920 Charl    \\\///  FIDONET: 2:231/84.45
Denmark           \XX/

comeau@ditka.Chicago.COM (Greg Comeau) (04/26/91)

In article <91113.092907GHGAQZ4@cc1.kuleuven.ac.be> GHGAQZ4@cc1.kuleuven.ac.be writes:
>I thought that ALL --x or ++x operators where to be evaluated BEFORE the
>evaluation of the total expression happens (and this is presumably also
>what happens) and that ALL x++ or x-- operators where to be evaluated
>AFTER the evaluation of the total expression (and this is presumably
>not true). This would seem more logical to me.

As this thread has amply demonstrated, the "total expression" is not
always the issue.  This is a ramification of the order of side-effects,
whose order is undefined.  Let's see now.... Ok, here is what ANSI C,
section 3.3 has to say:

   "the order of evaluation of subexpressions and the order in which
    side effects take place are both unspecified"

So, not only are we not told whethere the left of right hand side is
evaluated first in this (X)*(Y) situation where X and Y and --x et al,
but we are also not told when the post- and re-fixes are done either.
So yes, the --x will decrement the x before usage, however if that was
X and ++x was Y, the -- is not necessarily done first.

Taking what I'll call a strict look at all this, point in fact is that the
value of the expression is formally undefined even though most compilers
will generates some combinationally predicatable value.

- Greg
-- 
	 Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418
                            Producers of Comeau C++
          Here:attmail.com!csanta!comeau / BIX:comeau / CIS:72331,3421
                     Voice:718-945-0009 / Fax:718-441-2310

dillon@overload.Berkeley.CA.US (Matthew Dillon) (04/27/91)

In article <MWM.91Apr25103611@raven.pa.dec.com> mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) writes:
>In article <dillon.6879@overload.Berkeley.CA.US> dillon@overload.Berkeley.CA.US (Matthew Dillon) writes:
>	The ONLY three C operators that guarentee evaluation order are &&, ||,
>	and the comma as an operator (when not used in a subroutine call, where
>	it doesn't act as the comma operator).
>
>Don't forget ?:. It is (they are?) a trinary operator, and guarantees

    I *knew* I forgot something!  But people get the point...

>	++a + ++a
>
>	If a is 1, the result can be 2 + 2 or 2 + 3 or 3 + 2 and at the end 'a'
>	can be either 3 or 4 depending on how the compiler was designed.
>
>Actually, ANSI says the result is "undefined". Normally, you'll get
>one of the things you mentioned or 3 + 3, but there are oddball
>compilers out there that completely unexpected things.
>
>The bottom line is still the same - you don't want to do this kind of thing.
>
>	<mike

    Well, I think you are being picky mike since the two statements say
    basically the same thing.  Forgot about 3 + 3 (preinc done before
    either operand is evaluated), but again, it's the point that counts.

>--
>Tried to amend my carnivorous habits			Mike Meyer
>Made it nearly seventy days				mwm@pa.dec.com
>Loosing weight without speed				decwrl!mwm
>Eatin' sunflower seeds

					-Matt

--

    Matthew Dillon	    dillon@Overload.Berkeley.CA.US
    891 Regal Rd.	    uunet.uu.net!overload!dillon
    Berkeley, Ca. 94708
    USA

mwm@pa.dec.com (Mike (My Watch Has Windows) Meyer) (04/30/91)

In article <jsmoller.4971@jsmami.UUCP> jsmoller@jsmami.UUCP (Jesper Steen Moller) writes:
   ---- FICTIVE CODE START ----

   int func1(void);
   int func2(void);

   int result;

       result=func1()+func2();
   ---- FICTIVE CODE END ----

   Question: Can't you rely on func1() being called before func2()???
   Really not?

Really not.

   > 	++a + ++a
   > 
   >     If a is 1, the result can be 2 + 2 or 2 + 3 or 3 + 2 and at the end 'a'
   >     can be either 3 or 4 depending on how the compiler was designed. DO NOT
   >     DEPEND ON ANY PARTICULAR SIDE EFFECT WITH ++ or -- ACTING ON THE SAME
   >     VARIABLE MORE THAN ONCE IN ANY EXPRESSION, EVER, OR YOUR CODE WILL BE
   >     UNPORTABLE EVEN ACROSS REVISIONS OF THE SAME COMPILER!

   Oh, by the way: func(a++)

   Is "a" increased before or after the function call. I think I once read in
   K&R that it was undefined, but I might be mistaken.

I'm not sure what K&R said, but ANSI says that the arguments are
evaluated, then there's a sequence point, then the call happen. At
sequence points, all side effects must have taken place, so a will
have been incremented before the call.

	<mike
--
Es brillig war. Die schlichte Toven			Mike Meyer
Wirrten und wimmelten in Waben;				mwm@pa.dec.com
Und aller-mumsige Burggoven				decwrl!mwm
Die mohmem Rath' ausgraben.

farren@well.sf.ca.us (Mike Farren) (04/30/91)

jsmoller@jsmami.UUCP (Jesper Steen Moller) writes:

>    result=func1()+func2();

>Question: Can't you rely on func1() being called before func2()???
>Really not?

Nope.  Really not.  There is no guarantee at all that the compiler will
call func1 first - the only guarantee is that both functions will have
been called before the add takes place :-)

>Oh, by the way: func(a++)
>Is "a" increased before or after the function call. I think I once read in
>K&R that it was undefined, but I might be mistaken.

Nope, not undefined.  a is evaluated, and passed to the function when it
is called, and then is incremented.  This *is* guaranteed.
-- 
Mike Farren 				     farren@well.sf.ca.us