TURGUT@TREARN.BITNET (Turgut Kalfaoglu) (08/26/88)
The other day, I was struggling with QuickC - a very simply problem, but really intriguing. Let me know if you can interpret this: main() { int a,v; a = 2; v = square(a); printf("%d\n",v); } square(num) int num; { num = num*num; } OK? There is no 'return' statement in the function. However, it works! I get '4' as an answer. So I thought maybe it was keeping the result of the last operation, so I added some dummy lines, square(num) int num; { int dummy; num = num*num; dummy=222; } but the call STILL works... Can anyone shed some light onto this? WHY does it work? -turgut
chris@mimsy.UUCP (Chris Torek) (08/27/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU> TURGUT@TREARN.BITNET (Turgut Kalfaoglu) noticed some wrong code that worked anyway: >square(num) int num; { num = num*num; } >... There is no 'return' statement in the function. However, it works! >... I thought maybe it was keeping the result of the last operation, >so I added some dummy lines, >square(num) int num; { int dummy; num = num*num; dummy=222; } >but the call STILL works... WHY does it work? Luck. More seriously: it is due to a combination of the compiler and the machine architecture. The compiler does a multiply by loading the multiplicand and multiplier (in this case, num and num) into one or more registers (here, one suffices), multiplying the registers, and perhaps storing the result (the store may well be deleted by a dead-store checker). For whatever reason, it chooses the same register that the compiler/architecture uses for integer return values. The dummy assignment is either eliminated completely by a dead-store checker, or else is done by a memory-to-memory or immediate-to-memory move, which does not overwrite that register. Then, since there is no return statement at all, nothing is put into the return-value register, leaving the old num*num result. A more common occurrence of this same bug appears as follows: /* caller: */ var = fn(args); ... int fn(args) { ...; otherfn(otherargs); } int otherfn(args) { ...; return (expr); } On architectures with a common return-value register---e.g., VAX (r0), Intel 80*86 (ax), MC680X0 (d0)---this works. Fortunately, lint catches this sort of error, before you attempt to run the code on a Pyramid.... -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
swilson%thetone@Sun.COM (Scott Wilson) (08/27/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU> TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: >main() >{ > int a,v; > a = 2; > v = square(a); > printf("%d\n",v); >} > >square(num) >int num; >{ > num = num*num; >} >WHY does it work? I get the same behavior on a Sun running 3.5 (but not 4.0). The reason it works is that the scratch register used for the multiplication happens to be the same register that is used to return the function's value (in my case d0). The reason that adding the assignment to dummy didn't change anything is that this most likely didn't involve any registers, the value was stored directly in memory since dummy is on the stack. Under SunOS 4.0 this gives the answer 0. For some reason all functions without an explicit return statement return 0. I think it has something to do with compatibility with 4.3 BSD where return(x) in main() is the same as exit(x). Since main() often ends without a return (or exit() being called) it could cause problems if a random register value were used for the exit code. So, main() without a return returns zero which is a "successfull" termination in UNIX. -- Scott Wilson arpa: swilson@sun.com Sun Microsystems uucp: ...!sun!swilson Mt. View, CA
vch@attibr.UUCP (Vincent C. Hatem) (08/27/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU>, TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: > The other day, I was struggling with QuickC - a very simply problem, > but really intriguing. Let me know if you can interpret this: > main() > { > int a,v; > a = 2; > v = square(a); > printf("%d\n",v); > } > square(num) > int num; > { > num = num*num; > } > OK? There is no 'return' statement in the function. However, it works! > I get '4' as an answer. So I thought maybe it was keeping the result I took the above program, copied it with the swipe of a mouse, and compiled it... I get: $ cc test1.c -o test1 $ test1 -1073610208 Hmm... What's this QuickC??? An interpreter? I suspect that the compiler is putting the variable "num" on the stack, which is being picked up by the main(). I guess AT&T got something right ;-} Vince -- Vincent C. Hatem | att ---->\ (available from any AT&T International | ulysses ->\ Action Central site) International Operations Technical Support | bellcore ->\ 1200 Mt Kemble Ave, Basking Ridge, NJ 07920 | ihnp4 ----->\__ !attibr!vch
leo@philmds.UUCP (Leo de Wit) (08/27/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU> TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: | |The other day, I was struggling with QuickC - a very simply problem, |but really intriguing. Let me know if you can interpret this: | |main() |{ | int a,v; | a = 2; | v = square(a); | printf("%d\n",v); |} | |square(num) |int num; |{ | num = num*num; |} | |OK? There is no 'return' statement in the function. However, it works! |I get '4' as an answer. So I thought maybe it was keeping the result |of the last operation, so I added some dummy lines, | |square(num) |int num; |{ | int dummy; | num = num*num; | dummy=222; |} | |but the call STILL works... Can anyone shed some light onto this? |WHY does it work? |-turgut My guesses (I don't know QuickC, but I can understand why it would behave like this): In the first case: The return value of a C function is typically returned in a register (if it fits in one); often the compiler uses one and the same register. Also for temporary values mostly a small set of registers is used; if the temporary value num * num happens to be put into the same register, the above behaviour is explained. In the second case: The '222' can be directly assigned (to dummy) so that no temporary is needed; the num * num result is still in the 'temporaries' register. Other possible explanation: if the compiler is really smart it could see that dummy is assigned but never used and so optimized it away. Leo.
pcm@iwarpj.intel.com (Phil C. Miller) (08/29/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU> TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: >The other day, I was struggling with QuickC - a very simply problem, >but really intriguing. Let me know if you can interpret this: >main() >{ > int a,v; > a = 2; > v = square(a); > printf("%d\n",v); >} >square(num) >int num; >{ > num = num*num; >} >OK? There is no 'return' statement in the function. However, it works! >I get '4' as an answer. So I thought maybe it was keeping the result >of the last operation, so I added some dummy lines, >square(num) >int num; >{ > int dummy; > num = num*num; > dummy=222; >} >but the call STILL works... Can anyone shed some light onto this? >WHY does it work? >-turgut Don't know for sure, but I'll offer a conjecture: The subprogram calling standard for Microsoft C probably has a register doing double duty: it holds input arguments (i.e., num) and also holds the function result (unassigned, but with a residual value set when you assigned a value to the input argument num. Another conjecture: if you were using an optimizing compiler, it would see that the value num was dead (i.e., had no further use in the function square) and the assignment to num would disappear, along with the 'magic' function value assignment. Phil Miller {...}!tektronix!omepd!iwarp!pcm
daveh@marob.MASA.COM (Dave Hammond) (08/29/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU> TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: > >The other day, I was struggling with QuickC - a very simply problem, >but really intriguing. Let me know if you can interpret this: > >[... examples pertaining to square() returning a correct value even tho' it >(a) has no return statement or (b) has a dummy return value. ...] My guess is that there is a QuickC library routine called square() which is being loaded before your routine, and thus called in lieu of yours. Another answer might be a #define somewhere, like: #define square(x) ((x)*(x)) Is there any loader/linker warning message about multiply-defined square() ? Dave Hammond UUCP: {uunet|...}!masa.com!{dsix2|marob}!daveh DOMAIN: dsix2!daveh@masa.com ------------------------------------------------------------------------------
daveb@laidbak.UUCP (Dave Burton) (08/29/88)
In article <8808261424.AA11504@ucbvax.Berkeley.EDU> TURGUT@TREARN.BITNET (Turgut Kalfaoglu) writes: |[in QuickC] |square(num) int num; { num = num*num; } | |...I get '4' as an answer...[then I tried] | |square(num) |int num; |{ | int dummy; | num = num*num; | dummy=222; |} | |but the call STILL works... Can anyone shed some light onto this? |WHY does it work? The result of the _calculation_ was placed into the register used to return the value to the caller (ax?). The addition of the _assignment_ did not have to disturb this register. Try using "dummy=222*num;" instead. This will force another calculation, and should overwrite the `correct' result. -- Dave Burton | ``/* You are not expected to understand this. */'' {spl1,sun}!laidbak!daveb| (312) 505-9100 x325 | Disclaimer: I channel only for myself.