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