fauman@cgl.ucsf.edu (Eric Fauman%Stroud) (11/24/87)
In article <569@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes: > >What I'm wondering is this: if that's the case, then shouldn't > > printf("%05d", -20); > >have as its output "00-20"? > it does, in VAX C at least
jdm@hodge.UUCP (jdm) (04/26/89)
Perhaps someone could explain this printf() phenomena to me. I have a file with binary data. I want to read four consecutive bytes from the file and display them with printf(). The data in in the file in hex is: 92 AB 4E 33 I fopen() the file in binary mode and used the following line of code to read and print out the data: printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); Although the order of the data in the file is: 92 AB 4E 33 printf() displays it as: 33 4E AB 92 Just the reverse of its order in the file. Changing the code to: a = getc(fp); b = getc(fp); c = getc(fp); d = getc(fp); printf("%x %x %x %x\n", a, b, c, d); solves the problem, but why did printf() screw the order up when I used getc() directly? How might I correct this? This happens in both Turbo C 2.0 and MS C 5.1.
zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") (04/26/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > > Perhaps someone could explain this printf() phenomena to me. > > I have a file with binary data. I want to read four consecutive > bytes from the file and display them with printf(). The data > in in the file in hex is: > > 92 AB 4E 33 > > I fopen() the file in binary mode and used the following line > of code to read and print out the data: > > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > > Although the order of the data in the file is: > > 92 AB 4E 33 > > printf() displays it as: > > 33 4E AB 92 > > Just the reverse of its order in the file. > C puts its function parameters on the stack in "reverse" order, i.e. the last item is on top (this allows variable number of parameters for user defined functions). Thus, the last item is accessed FIRST. So what is happening is the last getc(fp) is called first and hence the reversal. > Changing the code to: > > a = getc(fp); > b = getc(fp); > c = getc(fp); > d = getc(fp); > > printf("%x %x %x %x\n", a, b, c, d); > > solves the problem, but why did printf() screw the order up when > I used getc() directly? How might I correct this? What you did will correct it. Or try: for ( i = 0; i < 4; ++i ) { printf( "%x ", getc(fp) ); } printf( "\n" ); Of course, where you are gaining in not having to declare 4 variables, you are losing in 5 calls of printf. Trade-offs, trade-offs ... > > This happens in both Turbo C 2.0 and MS C 5.1. It would happen in any C. Tom. -- This is my signature: tom zougas
bph@buengc.BU.EDU (Blair P. Houghton) (04/26/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > > Perhaps someone could explain this printf() phenomena to me. [...wherein printf scrambles the variable-arguments to produce an unintended ordering of the numbers on the printout...] Oh, Dr. Torek? Isn't there an automated version of this answer in the comp.lang.c.chestnuts archive? The reason that printf scrambles arguments after the format statement is that there is no requirement anywhere detailing the order of evaluation of the arguments to a function. Apparently, in this instance, since the arguments were evaluated in reverse order, the passing of arguments in your C must be done with a LIFO stack, hence the last argument passed is the first one evaluated, and so on. [...second-try at debugging:] > a = getc(fp); > b = getc(fp); > c = getc(fp); > d = getc(fp); > > printf("%x %x %x %x\n", a, b, c, d); Ah, now the arguments aren't functions being evaluated, they're just variables being dereferenced. See, putting 'getc(fp) where you have d in the printf would mean that that getc() would be evaluated _before_ the c was dereferenced, then the b, then the a. Since the behavior of the particular function does specify how to arrange the returned values of the argument-evaluation, you get the output as a b c (whatever my getc returned) even though the first one that printf really knew the answer to was the getc. If there are compilers that do it the other way (FIFO stack for args), I don't know about them. You're best bet, however, is not to trust the order of evaluation of arguments, regardless. Common mistake, really. I found out about it the same way you are. And, no, I didn't go back and check all my old code, neither. --Blair "...you can only be just so responsible, y'kno?"
gwyn@smoke.BRL.MIL (Doug Gwyn) (04/26/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); The order of evaluation of function arguments in C is unspecified. Some implementations evaluate the last argument first, others don't. Since getc(fp) has a side effect (it advances an external stream), the order of evaluation matters in this example, therefore the code is not portable. Your solution works, as would a succession of four printf() invocations each printing one getc(fp) result.
gharris@secola.Columbia.NCR.COM (Buddy Harris) (04/27/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes:
-> I fopen() the file in binary mode and used the following line
-> of code to read and print out the data:
-> printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp));
-> Although the order of the data in the file is:
-> 92 AB 4E 33
-> printf() displays it as:
-> 33 4E AB 92
This is something that I don't understand either, but apparently
printf() evluates from right to left. Be careful with stetements like this:
printf("%d %d %d %d", i++, i++, i++, i++);
This evluates from right to left also.
--
------------------------------------------------------------------------------
! Sleep well and dream of large women. - The Dread Pirate Roberds !
! gharris@secola.Columbia.NCR.COM (George Harris) Have a nice day :-) !
------------------------------------------------------------------------------
tim@crackle.amd.com (Tim Olson) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: | In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: | C puts its function parameters on the stack in "reverse" order, i.e. | the last item is on top (this allows variable number of parameters | for user defined functions). Thus, the last item is accessed FIRST. So | what is happening is the last getc(fp) is called first and hence the | reversal. No, the order of evaluation of function arguments is undefined -- the notion of a stack does not necessarily exist. See K&R C language reference manual, section 7.1, or the pANS, section 3.3.2.2. | > | > This happens in both Turbo C 2.0 and MS C 5.1. | | It would happen in any C. Function arguments *tend* to be evaluated in "reverse order" on systems [meaning the combination of compiler and processor architecture] which pass arguments on a memory stack, because it is sometimes easier. However, systems which pass arguments in registers may reverse this, and optimizing compilers on certain processor architectures may take advantage of the undefined order of evaluation to minimize execution time by scheduling the use of processor resources. For example, on the Am29000, this sequence: ;f(int a, int *b, int c) sub gr1,gr1,24 asgeu V_SPILL,gr1,gr126 add lr1,gr1,44 ;{ ; return g(c+3,a-*b, *b); add lr2,lr10,3 <-- c+3 evaluated first load 0,0,lr4,lr9 <-- then *b call lr0,_g sub lr3,lr8,lr4 <-- a-*b evaluated last -- Tim Olson Advanced Micro Devices (tim@amd.com)
kremer@cs.odu.edu (Lloyd Kremer) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") writes: >C puts its function parameters on the stack in "reverse" order, i.e. >the last item is on top > >It would happen in any C. It's not C that specifies this behavior. C has never specified any order of evaluation for function arguments. C does not even presume the existence of a last-in-first-out stack onto which arguments could be pushed. Some implementations pass args in registers or through a static area reserved for the purpose. Some mix register passing and stack passing. Even in fully stack-based implementations where reverse ordering is the norm, it cannot be assumed in all cases. Vagaries of code generation or, more likely, subsequent optimization, can change the order of evaluation in specific cases. The correct solution is unchanged since the early days of C: do not assume anything regarding the order of evaluation of function arguments. -- Lloyd Kremer Brooks Financial Systems ...!uunet!xanth!brooks!lloyd Have terminal...will hack!
maart@cs.vu.nl (Maarten Litmaath) (04/27/89)
jdm@hodge.UUCP (jdm) writes:
\ printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp));
The ORDER in which the arguments are evaluated, is UNSPECIFIED.
Read any book on C.
--
"If it isn't aesthetically pleasing, |Maarten Litmaath @ VU Amsterdam:
it's probably wrong." (jim@bilpin). |maart@cs.vu.nl, mcvax!botter!maart
bradb@ai.toronto.edu (Brad Brown) (04/27/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > > I have a file with binary data. I want to read four consecutive > bytes from the file and display them with printf(). The data > in in the file in hex is: > > 92 AB 4E 33 > > I fopen() the file in binary mode and used the following line > of code to read and print out the data: > > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > > Although the order of the data in the file is: C makes no guarantees about the order in which arguments are evaluated -- K&R says this and several other places do to. That's why you CAN'T have functions with interdependant side effects in the argument list of a function call -- you can't say which one will execute first. Unfortunately your solution > a = getc(fp); > b = getc(fp); > c = getc(fp); > d = getc(fp); > > printf("%x %x %x %x\n", a, b, c, d); is (an) appropriate one because you have to get consecutive reads out of the argument list. (-: Brad Brown :-) bradb@ai.toronto.edu
karl@haddock.ima.isc.com (Karl Heuer) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: >In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: >> printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); >>[was found to evaluate the rightmost getc() first.] > >It would happen in any C. No. Not all hardware has a downward-growing stack, and even on those that do, not all C compilers evaluate function arguments in the same order that they are pushed. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
gwyn@smoke.BRL.MIL (Doug Gwyn) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: >C puts its function parameters on the stack in "reverse" order, ... Not necessarily. >It would happen in any C. No.
gwyn@smoke.BRL.MIL (Doug Gwyn) (04/27/89)
In article <353@secola.Columbia.NCR.COM> gharris@secola.Columbia.NCR.COM (Buddy Harris) writes: >This is something that I don't understand either, but apparently >printf() evluates from right to left. Be careful with stetements like this: > printf("%d %d %d %d", i++, i++, i++, i++); >This evluates from right to left also. Despite there having been several correct (and several incorrect) postings about this already, I think it is important to understand exactly what is going on here. It is not the case that printf() is evaluating its arguments. The compiler generates code that evaluates the arguments BEFORE the call is made to the printf() function. There are several contexts in C where the exact order of evaluation is deliberately not specified by the language, leaving it up to the implementation (i.e. compiler) to select whatever is most efficient or most convenient. It would have been possible in principle for the C language specification to have included a requirement that function arguments be evaluated in a certain order; indeed, first-to-last, i.e. left-to-right in our culture, would have been the natural order to specify. Why, then, was this left unspecified? The answer has to do with the details of implementing function-call linkage. Briefly, machine architectures vary widely. It may well happen, as it does on many modern stack-based architectures, that the most efficient way to implement function linkage involves pushing the last (rightmost) argument datum onto the hardware stack first, so that the first function parameter is the one nearest the top of the stack. This is to some extent influenced by the existence of variadic functions such as printf(). For other architectures (typically non stack-based ones), it may be more efficient to store the first (leftmost) argument datum first. In order to allow implementations the flexibility to select the fastest method for function linkage, C does not require either choice, and this is reflected in the unspecified order of argument evaluation. By the way, it is easy to give incorrect arguments based on whether stacks most naturally grow upward or downward on the architecture. Lacking some requirement for function parameters having to be in a particular address order (which I was unable to come up with), the "natural" direction of stack growth isn't really a factor.
dondorp@uva.UUCP (Erwin Dondorp (I84)) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: >[stuff deletd] >[arguments of a function are evaluated in the reverse order] >It would happen in any C. NO. I have a compiler that really evaluates the arguments in the order that you specified, That thus makes the statement 'any C' to become untrue. Erwin Dondorp
wietse@wzv.UUCP (Wietse Z. Venema) (04/27/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); The order of evaluation of the printf argument is not defined. Some compilers evaluate right to left, as you seem to experience. -- work: wswietse@eutrc3.uucp | Eindhoven University of Technology work: wswietse@heitue5.bitnet | Mathematics and Computing Science home: wietse@wzv.uucp | Eindhoven, The Netherlands
paul@moncam.co.uk (Paul Hudson) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca>, zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") writes: > In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > > > > Perhaps someone could explain this printf() phenomena to me. ... > > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > C puts its function parameters on the stack in "reverse" order, i.e. > ... No. C does not have any order defined for function evaluation. Typically compilers derived from pcc or that pass args. purely on the stack will push in reverse order, but even this isn't defined. Don't rely on it! > What you did will correct it. Or try: Sometimes, if the wind is in the right direction. > for ( i = 0; i < 4; ++i ) { > printf( "%x ", getc(fp) ); > } > you are losing in 5 calls of printf. Trade-offs, trade-offs ... The above works, the original doesn't, neither does the first fix always. > > It would happen in any C. No. See above. > Tom. > -- Paul Hudson MAIL: Monotype ADG, Science Park, Cambridge, CB4 4FQ, UK. PHONE: +44 (223) 420018 EMAIL: paul@moncam.co.uk, FAX: +44 (223) 420911 ...!ukc!acorn!moncam!paul "/dev/null full: please empty the bit bucket"
thomas@uplog.se (Thomas Hameenaho) (04/27/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes:
Perhaps someone could explain this printf() phenomena to me.
I have a file with binary data. I want to read four consecutive
bytes from the file and display them with printf(). The data
in in the file in hex is:
92 AB 4E 33
I fopen() the file in binary mode and used the following line
of code to read and print out the data:
printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp));
printf() displays it as:
33 4E AB 92
The problem is that the evaluation order of the arguments to printf (in
this case) is not defined in C. One should NOT have expressions with
sideeffects in function calls. The code will be inherently non-portable.
--
Real life: Thomas Hameenaho Email: thomas@uplog.{se,uucp}
Snail mail: TeleLOGIC Uppsala AB Phone: +46 18 189406
Box 1218 Fax: +46 18 132039
S - 751 42 Uppsala, Sweden
dave@micropen (David F. Carlson) (04/27/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca>, zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") writes: ! In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: ! > ! > Perhaps someone could explain this printf() phenomena to me. ! > ! > This happens in both Turbo C 2.0 and MS C 5.1. ! ! It would happen in any C. ! ! tom zougas Well, actually it *can* happen in any C. If it did happen in every C then order of evaluation of function parameters *would* be guaranteed, wouldn't it?! 1/2 :-) -- David F. Carlson, Micropen, Inc. micropen!dave@ee.rochester.edu "The faster I go, the behinder I get." --Lewis Carroll
) Seaman) (04/28/89)
zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") writes: < jdm@hodge.UUCP (jdm) writes: < > Perhaps someone could explain this printf() phenomena to me. [printf example deleted...] < C puts its function parameters on the stack in "reverse" order, i.e. < the last item is on top (this allows variable number of parameters < for user defined functions). Thus, the last item is accessed FIRST. So < what is happening is the last getc(fp) is called first and hence the < reversal. Actually, this is not quite true. Since there is no specification in ANSI or K&R regarding the order of evaluation of arguments to a function, the actual processing is compiler dependent. Some will evaluate in a last in, first out (LIFO) order, and some in a FIFO order. You have no guarantees, though. < What you did will correct it. Or try: < < for ( i = 0; i < 4; ++i ) { < printf( "%x ", getc(fp) ); < } < printf( "\n" ); < < Of course, where you are gaining in not having to declare 4 variables, < you are losing in 5 calls of printf. Trade-offs, trade-offs ... I hope this doesn't start a flame war, but IMHO, you should NEVER use a function with all the overhead of printf() to output a simple linefeed. putchar() or fputc() would do the same job, without all the overhead. < Tom. < -- Chris Seaman | o\ /o crs@cpsc6a.att.com <or> | || See "Attack of the Killer Smiley"! ..!ihnp4!cpsc6a!crs | \vvvvvv/ Coming Soon to a newsgroup near you! | \____/
jdm@hodge.UUCP (jdm) (04/28/89)
Thanks to all who responded to my question about printf(). I'm an anthropologist, not a computer programmer, damit! -- jdm@hodge.cts.com [uunet zardoz vdelta crash]!hodge!jdm James D. Murray, Ethnounixologist Hodge Computer Research Corporation 1588 North Batavia Street Orange, California 92667 USA TEL: (714) 998-7750 Ask for James FAX: (714) 921-8038 Wait for the carrier
zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") (04/28/89)
In article <703@uva.UUCP> dondorp@uva.UUCP (Erwin Dondorp (I84)) writes: >In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: >>[stuff deletd] >>[arguments of a function are evaluated in the reverse order] >>It would happen in any C. > >NO. > > >I have a compiler that really evaluates the arguments in the order that >you specified, That thus makes the statement 'any C' to become untrue. > I should have said: "It could/might/.. happen in any C. Therefore, don't rely on order of evaluation. As a matter of fact, Kernighan & Ritchie state in _The C Programming Language_ , page 212: 'order of evaluation of function arguments is not specified by the language'." I apologize for my imprecision. Why do I feel like a scolded child :-? Tom. -- This is my signature: tom zougas
kevinf@infmx.UUCP (Kevin Franden) (04/28/89)
In article <518@cpsc6b.cpsc6a.att.com> crs@cpsc6b.cpsc6a.att.com (Chris (I'm Outta Here!) Seaman) writes: >zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") writes: >< jdm@hodge.UUCP (jdm) writes: >< > Perhaps someone could explain this printf() phenomena to me. > >[printf example deleted...] > [other stuff deleted...] >< What you did will correct it. Or try: >< >< for ( i = 0; i < 4; ++i ) { >< printf( "%x ", getc(fp) ); >< } >< printf( "\n" ); >< >< Of course, where you are gaining in not having to declare 4 variables, >< you are losing in 5 calls of printf. Trade-offs, trade-offs ... > >I hope this doesn't start a flame war, but IMHO, you should NEVER use >a function with all the overhead of printf() to output a simple linefeed. >putchar() or fputc() would do the same job, without all the overhead. > Um.... isn't the last printf "for free" 'cause it's already linked in from the other call? Once you call a routine it doesn't matter how MANY times you call it, right? I agree that it would be better to use puts(" ") or somthing (anything!) with less overhead to do such a trivial operation like printing a NL, but if you already used the (big, complex) code of printf, why not reuse it? Unless you're REAL concerned about saving clock cycles (puts being faster)... -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Kevin Franden UUCP: {backbone}!pyramid!infmx!kevinf Informix Software Inc disclaimer("I said what I said and not my employer"); =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
geoff@cs.warwick.ac.uk (Geoff Rimmer) (04/28/89)
In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > > Although the order of the data in the file is: > > 92 AB 4E 33 > > printf() displays it as: > > 33 4E AB 92 > > Just the reverse of its order in the file. The 5 arguments to printf() are being pushed onto the stack, starting from the 5th back thru the 1st (the format string). There is nothing odd with this. When a C compiler is written, the author can evaluate arguments to functions in anyway he/she likes. Last to first, first to last, or even the even arguments followed by the odd ones! So, you should never have the code: main() { int i=1; printf("%d %d %d %d\n",i++,i++,i++,i++); } since some compilers will print 1 2 3 4 others will print 4 3 2 1 an a weird one might print 3 2 1 4 So, you cannot and must not rely on any particular behaviour. What works for your compiler may not work with another. Geoff /---------------------------------------------------------------\ | GEOFF RIMMER - Friend of fax booths, ANSI C, PCBH, | | phone *numbers* & MPFC & printf | | email : geoff@uk.ac.warwick.emerald | | address : Computer Science Dept, Warwick University, | | Coventry, England. | | PHONE : +44 203 692320 (10 lines) If I'm out please | | leave a message with my secretary. | | FAX : +44 865 726753 | \---------------------------------------------------------------/
mat@mole-end.UUCP (Mark A Terribile) (04/28/89)
In article <11657@hodge.UUCP>, jdm@hodge.UUCP (jdm) writes: > > Perhaps someone could explain this printf() phenomena to me. > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > > Although the order of the data in the file is: > 92 AB 4E 33 > printf() displays it as: > 33 4E AB 92 > Just the reverse of its order in the file. The compiler wrote code which evaluated the arguments to printf() in reverse order. There is no guarantee of in what order the parameters to printf() will be evaluated, but there is a rationale that let's you guess pretty well what the compiler will do. Y'see, it's pretty much required that when printf() is invoked, it see its arguments as a (non-homogeneous) array, with arg N+1 at an address higher than arg N. This may now be a requirement of ANSI C; I don't know. Certainly it makes it more nearly possible to write a GOOD varargs package. On ``most machines'' or ``many machines'' and probably ``the machine on which you work'' the stack grows downward; the N+1th object pushed is at an address lower than the Nth object. In order to get then N+1th arg at a higher address than the Nth, they are evaluated in reverse order. (Yes, it would be possible to evaluate them in normal order and reverse them, but what a pain, especially for objects of differing sizes.) The lesson is simple: don't depend on the order in which arguments are evaluated. Sooner or later, on some machine, it will be wrong. -- (This man's opinions are his own.) From mole-end Mark Terribile
guy@auspex.auspex.com (Guy Harris) (04/28/89)
>C puts its function parameters on the stack in "reverse" order, No, the C implementation being described happens to do so. C has no notion of "the stack", and it certainly has no notion that the function parameters are "put onto the stack" in some particular order, or even that those arguments are *evaluated* in some particular order! To quote, yet again, from the pANS: 3.3.2.2 Function calls ... Semantics ... The order of evaluation of the function designator, the arguments, and subexpressions within the arguments is unspecified, but there is a sequence point before the actual call. >> This happens in both Turbo C 2.0 and MS C 5.1. > >It would happen in any C. Guess again. A C implementation could, if it wished, evaluate the four function calls in the arguments in the "printf" call from left-to-right, right-to-left, or in any other order that it chose. Do NOT write code that depends on them being evaluated in ANY particular order, unless you 1) absolutely positively MUST have code of that sort and 2) absolutely postively KNOW that your code will only be used on implementations where the arguments are evaluated in the particular order in which you expect them to be evaluated.
ftw@masscomp.UUCP (Farrell Woods) (04/28/89)
In article <353@secola.Columbia.NCR.COM> gharris@secola.Columbia.NCR.COM (Buddy Harris) writes: >This is something that I don't understand either, but apparently >printf() evluates from right to left. Be careful with stetements like this: > printf("%d %d %d %d", i++, i++, i++, i++); >This evluates from right to left also. DO NOT depend on this being true in all cases! The compiler is free to evaluate arguments in whatever order it sees fit. Your compiler may evaluate the arguments in that printf call from right to left, but another may quite reasonably evaluate them left to right. If the expressions have side effects, and you're depending on the order in which those side effects happen, you have non-portable code. -- Farrell T. Woods Voice: (508) 392-2471 Concurrent Computer Corporation Domain: ftw@masscomp.com 1 Technology Way uucp: {backbones}!masscomp!ftw Westford, MA 01886 OS/2: Half an operating system
friedl@vsi.COM (Stephen J. Friedl) (04/28/89)
[talking about why printf() "rearranges" the order of its arguments] In article <2679@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes: > > If there are compilers that do it the other way (FIFO stack for args), > I don't know about them. You're best bet, however, is not to trust > the order of evaluation of arguments, regardless. Actually, they're all FIFO stacks. It's been my observation that args are evaluated right-to-left on machines where the stack grows down and left-to-right if the stack grows up. The WE32100 (AT&T 3B2) and I think the PDP-11 all have an up-growing stack, and they operate this way. I don't know if it's a cause-and-effect relationship, but once I studied this and it seemed plausible guess. Steve P.S. - A *FIFO* stack? -- Stephen J. Friedl / V-Systems, Inc. / Santa Ana, CA / +1 714 545 6442 3B2-kind-of-guy / friedl@vsi.com / {attmail, uunet, etc}!vsi!friedl As long as Bush is in office, you'll never see Nancy Reagan in *my* .sig.
art@dinorah.wustl.edu (Arthur B. Smith) (04/28/89)
In article <11657@hodge.UUCP>, jdm@hodge.UUCP (jdm) writes: > > I have a file with binary data. I want to read four consecutive > bytes from the file and display them with printf(). The data > in in the file in hex is: > > 92 AB 4E 33 > > I fopen() the file in binary mode and used the following line > of code to read and print out the data: > > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > > Although the order of the data in the file is: > > 92 AB 4E 33 > > printf() displays it as: > > 33 4E AB 92 > In Kernighan and Ritchie, 2nd Edition it states: "The order of evaluation of arguments is unspecified; take note that various compilers differ. However, the arguments and the function designator are completely evaluated, including all side effects, before the function is entered." In particular in cc, vcc and gcc under Ultrix 3.0 on a microvax, and presumably in your compilers (MS5.1 and TurboC) printf happens to evaluate its arguments in reverse order. To verify this, try the program: main ( ) {int x = 0; printf("%d, %d, %d\n", ++x, ++x, ++x); } You will probably get 3, 2, 1 as your output. It is not safe to assume that function arguments are evaluated in any particular order. Normally this is not a problem, but when functions have side-effects (as essentially all i/o functions do), this can cause confusion. This was a good question! -art smith (art@dinorah.wustl.edu, ...!uunet!wucs1!dinorah!art)
jdurko@iemisi.UUCP (John Durko) (04/29/89)
In article <11657@hodge.UUCP>, jdm@hodge.UUCP (jdm) writes: > Perhaps someone could explain this printf() phenomena to me. > > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); > > Although the order of the data in the file is: > > 92 AB 4E 33 > > printf() displays it as: > > 33 4E AB 92 The problem here ( I think :-} ) is that the compiler is pushing the function arguments on the stack from right to left. Therefore the last argument on the list is the first to be evaluated and the thus makes the first call to getc(). The following code illustrates this: #include <stdio.h> main(){ int i = 1; printf(" %d %d %d %d \n",i++,i++,i++,i++); } Compiled and run this produces 4 3 2 1 . Can anybody tell me if this behavoir is "guaranteed" in C. I know that each argument expression must be evaluated fully before the next but could find no "guarantee" on the order that it is done. -- ______________________________________________________________________________ ___ ___ ___ ___ _ ___ / / / / / / /| / / John Durko, Boeing Canada, Toronto. /-- / / /-- / / | / / - The opinions expressed herein are not /__/ /__/ /__ _/_ / / /__/ official until the urinalysis results de Havilland Division are in!!! UUCP: {geac|utzoo|utgpu}!syntron!jtsv16!marsal1!iemisi!jdurko {uunet|suncan}!jtsv16!marsal1!iemisi!jdurko
dierks@ndmath.UUCP (Tim Dierks) (04/29/89)
From article <163@marvin.moncam.co.uk>, by paul@moncam.co.uk (Paul Hudson): < In article <89Apr26.092233edt.18850@me.utoronto.ca>, zougas@me.utoronto.ca ("Athanasios(Tom) Zougas") writes: <> In article <11657@hodge.UUCP> jdm@hodge.UUCP (jdm) writes: <> > <> > Perhaps someone could explain this printf() phenomena to me. < ... <> > printf("%x %x %x %x\n", getc(fp), getc(fp), getc(fp), getc(fp)); < <> C puts its function parameters on the stack in "reverse" order, i.e. <> ... < No. C does not have any order defined for function evaluation. Typically < compilers derived from pcc or that pass args. purely on the stack will < push in reverse order, but even this isn't defined. Don't rely on it! I understand that the _order_ of evaluation is undefined... My question is if the stack-based method of passing arguments, or the order in which the arguments are passed, is part of the C definition. The alternative seems to me to be making all functions that take a variable number of arguments non-portable. Is this the case? Tim Dierks dierks@darwin.cc.nd.edu
carroll@s.cs.uiuc.edu (04/29/89)
/* Written 6:01 pm Apr 28, 1989 by dierks@ndmath.UUCP in s.cs.uiuc.edu:comp.lang.c */ ( ... ) The alternative seems to me to be making all functions that take a variable number of arguments non-portable. Is this the case? /* End of text from s.cs.uiuc.edu:comp.lang.c */ No more than the fact the different systems have different IO setups makes using stdin/stdout/etc. non-portable. There is a standard method for doing variadic arguments ("varargs") that takes care of the non-portable parts, just as stdio.h takes care of IO differences. Alan M. Carroll "And there you are carroll@s.cs.uiuc.edu Saying 'We have the Moon, so now the Stars...'" CS Grad / U of Ill @ Urbana ...{ucbvax,pur-ee,convex}!s.cs.uiuc.edu!carroll
jimp@sunray.UUCP (Jim Patterson) (04/30/89)
In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: >C puts its function parameters on the stack in "reverse" order, i.e. >the last item is on top (this allows variable number of parameters >for user defined functions). It would happen in any C. It doesn't happen in "any" C. While reverse order is commonly chosen by C implementations, in fact the order is deliberately left unspecified by the language. Other implementations will choose to evaluate parameters in first to last order, or they could use first, third, fourth, second in a given instance, etc. A good compiler might generate two results in registers, in order, and push them with a single instruction. (I think the VAX/VMS C compiler might actually do this using a VAX PUSHQ instruction). In short, don't rely on evaluation order (and in particular avoid side-effect dependencies like in the printf(getc(),getc()) example). -- Jim Patterson Cognos Incorporated UUCP:decvax!utzoo!dciem!nrcaer!cognos!jimp P.O. BOX 9707 PHONE:(613)738-1440 3755 Riverside Drive Ottawa, Ont K1G 3Z4
bph@buengc.BU.EDU (Blair P. Houghton) (04/30/89)
In article <1109@vsi.COM> friedl@vsi.COM (Stephen J. Friedl) writes: >[talking about why printf() "rearranges" the order of its arguments] > >In article <2679@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes: >> >> If there are compilers that do it the other way (FIFO stack for args), > >Actually, they're all FIFO stacks. > >P.S. - A *FIFO* stack? Okay, a FIFO memory-worm... --Blair ":o)"
henry@utzoo.uucp (Henry Spencer) (04/30/89)
In article <1367@ndmath.UUCP> dierks@ndmath.UUCP (Tim Dierks) writes: > I understand that the _order_ of evaluation is undefined... My question >is if the stack-based method of passing arguments, or the order in which >the arguments are passed, is part of the C definition. The alternative >seems to me to be making all functions that take a variable number of >arguments non-portable. Is this the case? No definition of C mandates a stack, or any ordering of arguments within anything. Variadic functions need to use non-portable machinery to pick up their arguments, although modern practice is to encapsulate said machinery inside macros with portable interfaces, like <varargs.h> or <stdarg.h>. Stacks are actually usually a bad way of passing arguments. Passing at least the first two or three parameters in registers is often superior. (Although it complicates <varargs.h> etc., and can break crufty old programs.) -- Mars in 1980s: USSR, 2 tries, | Henry Spencer at U of Toronto Zoology 2 failures; USA, 0 tries. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
guy@auspex.auspex.com (Guy Harris) (05/02/89)
>My question is if the stack-based method of passing arguments, or the >order in which the arguments are passed, is part of the C definition. No, it's not. >The alternative seems to me to be making all functions that take a >variable number of arguments non-portable. No, it's not. >Is this the case? No, it's not. If you use the "stdarg.h" mechanism in the (p)ANS, any (p)ANS-conforming compiler is obliged to perform whatever magic is necessary to make that mechanism work. If you use the "varargs.h" mechanism supported by many C implementations, the compiler is again supposed to perform whatever magic is necessary to make that mechanism work. However, if you take the address of one of the arguments and use it to step through the argument list yourself, you run the risk of having your code not work on some implementations - but then, that style of variable-number-of-arguments function isn't portable.
ftw@masscomp.UUCP (Farrell Woods) (05/03/89)
In article <1367@ndmath.UUCP> dierks@ndmath.UUCP (Tim Dierks) writes: > I understand that the _order_ of evaluation is undefined... My question >is if the stack-based method of passing arguments, or the order in which >the arguments are passed, is part of the C definition. The alternative >seems to me to be making all functions that take a variable number of >arguments non-portable. Is this the case? You'd have a hell of a time implementing C on some architectures if the standard constrained argument passing like that. The method, order, etc. are not specified. Some C compilers will even pass the first couple of arguments in registers, then the rest on the stack. Don't depend on the order of evaluation of argument expressions. Don't depend on the order in which they are pushed onto the stack. Don't depend that they will all be on a stack, even on stack based machines. -- Farrell T. Woods Voice: (508) 392-2471 Concurrent Computer Corporation Domain: ftw@masscomp.com 1 Technology Way uucp: {backbones}!masscomp!ftw Westford, MA 01886 OS/2: Half an operating system
paulc@microsoft.UUCP (Paul Canniff 2/1011) (05/04/89)
In article <6006@sunray.UUCP> jimp@cognos.UUCP (Jim Patterson) writes: >In article <89Apr26.092233edt.18850@me.utoronto.ca> zougas@hammer.me.UUCP (Athanasios(Tom) Zougas) writes: >>C puts its function parameters on the stack in "reverse" order, i.e. >>the last item is on top (this allows variable number of parameters >>for user defined functions). It would happen in any C. > >It doesn't happen in "any" C. While reverse order is commonly chosen >by C implementations, I have no argument, just a clarification for those who belive that C and reverse-args are inseperable ... Rev-args IS usually chosen, because it facilitates variable-argument functions like printf(). However, it isn't the only way to do var-args. And indeed, even knowing the order of the parms on the stack doesn't give you a guarantee that they will always be *evaluated* in that order.
joe@gryphon.COM (Joseph Francis) (05/08/89)
The problem having been well characterized, why not a new specification for evaluation. The bitwise & operator is well-known to be commutative so it is left to the compiler to rearrange subterms for optimal evaluation, and therefore the 'deadly' getchar() used as getchar() & getchar() (useless, but similar to the original problem) combined with something else can have unpredictable side-effects. However, the getchar() && getchar() will always be L-R evaluated. So, for function definition, why not something like f(a, b; c; d, e, f) either in the prototype or at invocation which guarantees the ordering of b->c->d and leaves the others unspecified; mixed commtative and non-commutative argument delimiting. I realize, of course, this could be controlled with macros, something hideous like #def f(A,B,C) { argtype a,b,c; a=A; b=B; c=C; g(a,b,c) } or with better coding, but why not allow more sequencing control, if you allow it with && and other operators? -- joe@gryphon ...!elroy!gryphon!joe but jojo to my beeeest frieeeends.
karl@haddock.ima.isc.com (Karl Heuer) (05/09/89)
In article <15580@gryphon.COM> joe@gryphon.COM (Joseph Francis) writes: >[Why not have a variant of the comma punctuator that does guarantee L-R?] Because it's not useful enough to be worth adding the baggage to the language definition. If such a construct existed, I seriously doubt that it would get anywhere near as much use as `&&' does. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
henry@utzoo.uucp (Henry Spencer) (05/10/89)
In article <15580@gryphon.COM> joe@gryphon.COM (Joseph Francis) writes: >... So, for function >definition, why not something like f(a, b; c; d, e, f) either in the >prototype or at invocation which guarantees the ordering of b->c->d >and leaves the others unspecified... Why bother? -- Mars in 1980s: USSR, 2 tries, | Henry Spencer at U of Toronto Zoology 2 failures; USA, 0 tries. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
flaps@dgp.toronto.edu (Alan J Rosenthal) (05/15/89)
In article <15580@gryphon.COM> joe@gryphon.COM (Joseph Francis) writes: >The bitwise & operator is well-known to be commutative >so it is left to the compiler to rearrange subterms for optimal >evaluation, and therefore the 'deadly' getchar() used as >getchar() & getchar() (useless, but similar to the original problem) combined >with something else can have unpredictable side-effects. However, the >getchar() && getchar() will always be L-R evaluated. [ proposes a prototype f(a, b; c; d, e, f) which guarantees that b is evaluated before c which is evaluated before d ] I think you're paying insufficient attention to the other feature of `&&', namely that if the lhs is false the rhs is never evaluated. This could not have any analogue for the proposed `;' operator, because some function argument must still be supplied. I would maintain that the major use of `&&' is this conditional evaluation, not the sequencing. (Of course, the conditional evaluation implies the sequencing (in a non-parallel programming language), but not vice versa.) ajr -- "The winners write the history books."
zhao@csd4.csd.uwm.edu (T.C. Zhao) (10/21/89)
I recently came across a piece of c code:(both a and b are integers) printf("%d"+(a),b); in passes compiler without any problem, what does this code mean ? -- ---------------------------------------------- Internet: zhao@csd4.csd.uwm.edu BITNET: zhao%csd4.csd.uwm.edu@WISCMAC3.BITNET
henry@utzoo.uucp (Henry Spencer) (10/21/89)
In article <543@uwm.edu> zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: >printf("%d"+(a),b); >in passes compiler without any problem, what does this code mean ? In two words, "nothing useful". It feeds printf two arguments. The second is reasonably obvious. The first is a pointer somewhere into the string `"%d"'; for example, if `a' were 1, the pointer would point to the `d'. This almost certainly isn't what the programmer intended, although it *is* legal C if `a' is between 0 and 2 inclusive. -- A bit of tolerance is worth a | Henry Spencer at U of Toronto Zoology megabyte of flaming. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
chris@mimsy.umd.edu (Chris Torek) (10/21/89)
In article <543@uwm.edu> zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: >I recently came across a piece of c code:(both a and b are integers) >printf("%d"+(a),b); >in passes compiler without any problem, what does this code mean ? First, learn the language definition; then apply it. This is a function call to the `printf' function; it passes two arguments. The first argument (which is not necessarily evaluated first) is "%d" + (a) which is composed of three parts. The first part is a string constant. A string constant is an anonymous array of type `array N of char', where N is the number of characters in the string, plus one for a terminating NUL character (code 0). Here "%d" becomes the triple: <object, array 3 of char, `%d\0'> The third part of this expression is the sub-expression (a). In between these two parts is the `+' operator, which performs either scalar (integer or floating point) addition or pointer addition, depending on its arguments (the other two parts of the expression). These arguments are evaluated, meaning they are in `rvalue contexts'. Now we need to refer to the rule for handling array objects in rvalue contexts. The rule is: An object of type `array N of T' in an rvalue context is converted to a value of type `pointer to T' whose value is the address of the first element of that object. Thus, the value of <object, array 3 of char, `%d\0'> as seen by the `+' operator is <value, pointer to char, points to `%' in `%d\0'> The value of `(a)' is simply the value of the variable `a', which we were told above is an `integer' (presumably an |int|, not a |long|, nor |unsigned int| nor |unsigned long| nor any variety of |short| or |char|). Hence the arguments to the `+' operator are a pointer type and an integral type, and so `+' performs pointer addition. Pointer addition is done by moving forward some number of objects, the number being determined by the integral expression and the objects being determined by the pointer expression. Here the pointer points to |char|s, and the integral expression is the value of `a'. We do not know the value of `a', so we cannot predict the result of the pointer addition. The first part of our answer, then, is that we have no idea what value is being passed to printf() as its first argument. All we know is that it has type `pointer to char'. Returning to the printf() call, the second argument is the expression `b'. This is also in an rvalue context and so its value is the value of `b'. All we know about `b' is that it is an `integer', again presumably really an |int|, not a |short| or an |unsigned long| or some other type; but we do not really know that. The second part of our answer, then, is that we have no idea what value is being passed to printf() as its second argument. All we know is that it has one of the types |int|, |long|, |unsigned int|, or |unsigned long|; probably it is |int|. Finally, we put these together with knowledge about printf(). Printf expects its first argument to have type |pointer to char| (it does) and its remaining arguments, if any, are variadic (can be any rvalue type), but must match up with types that can be derived by examining the value of the first argument. In this case, we have no idea what that value might be. All we can conclude, then, is that printf() is being called with at least one correct type, and possibly two correct types. The answer to the question: >what does this code mean ? is thus `we cannot tell'. We can, however, make a guess or two at the intended meaning. The value passed to printf must be a pointer that points to at least one character. If that character is not NUL, it must be followed by at least one more character, and so on, until we reach a character that *is* NUL. The result of "%d"+(a) will not be a valid pointer to such a sequence of characters unless (a) has one of the three values 0, 1, or 2. These value causes the pointer addition `+' operator to evaluate to <value, pointer to char, points to `%' in `%d\0'> <value, pointer to char, points to `d' in `%d\0'> and <value, pointer to char, points to `\0' in `%d\0'> respectively. If `a' is 0, the expression reduces to printf("%d", b); which is correct (and prints to stdout the value of `b') iff `b' evaluates to an rvalue of type |int|. If `a' is 1, the expression reduces to printf("%d"+1, b); which acts like printf("d", b); which is correct regardless of the type of `b' (at least according to my draft of the proposed ANSI standard: excess arguments to printf are allowed and ignored). This prints to stdout the letter `d'. Finally, if `a' is 2, the expression reduces to printf("%d"+2, b); which acts like printf("", b); which is also always correct (as per above) and prints nothing at all. We can also conclude that if `a' has a value other than 0, 1, or 2, that the printf call is incorrect and the result is not predictable. (The result of "%d"+3 is legal but is not a pointer to one or more characters, hence the printf() can fail; and the result for other values is undefined, such pointer addition being illegal.) So our second answer to >what does this code mean ? is `either nothing at all, it being incorrect, if a is not 0, 1, or 2; or print the value of b; or print the letter d; or print nothing at all, if a is 0, 1, or 2 respectively.' Both answers depend upon some hidden assumptions, such as `the program contains the line ``#include <stdio.h>'' before the call to printf' and `a and b have values stored in them before the call to printf'. Without more information it is impossible to verify these assumptions. There are two lessons here: If you want to know what some code means, get a good book about C and apply it. and If you want someone to explain what some code does, you must be very explicit. Saying `a and b are integers' does not provide enough information---it does not even give the actual types of a and b. -- `They were supposed to be green.' In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
bobmon@iuvax.cs.indiana.edu (RAMontante) (10/22/89)
Henry Spencer and Chris Torek both tackle: zhao@csd4.csd.uwm.edu (T.C. Zhao) <543@uwm.edu> : -I recently came across a piece of c code:(both a and b are integers) -printf("%d"+(a),b); -in passes compiler without any problem, what does this code mean ? ... and the winner is --- CHRIS TOREK, by a score of 148 to 12!!! (lines of response, that is) [Maybe this code merely means that there was a careless C programmer once upon a time?]
gwyn@smoke.BRL.MIL (Doug Gwyn) (10/22/89)
In article <543@uwm.edu> zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: >I recently came across a piece of c code:(both a and b are integers) >printf("%d"+(a),b); >in passes compiler without any problem, what does this code mean ? It means what it says, namely the format string passed to printf() depends on the value of the variable a; a must be 0, 1, or 2 (corresponding to equivalent format strings "%d", "d", and ""), and in the latter two cases printf() will ignore the second argument (b). I can see using such a trick in some other cases, but this doesn't seem to be a wise use of it.
henry@utzoo.uucp (Henry Spencer) (10/22/89)
In article <28255@iuvax.cs.indiana.edu> bobmon@iuvax.cs.indiana.edu (RAMontante) writes: >Henry Spencer and Chris Torek both tackle [printf("%d"+(a),b);] ... >... and the winner is --- CHRIS TOREK, by a score of 148 to 12!!! >(lines of response, that is) In fairness, Chris gave a much more detailed and precise discussion of the possible uncertainties in the interpretation of the code fragment. -- A bit of tolerance is worth a | Henry Spencer at U of Toronto Zoology megabyte of flaming. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
fredex@cg-atla.UUCP (Fred Smith) (10/22/89)
In article <543@uwm.edu> zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: >I recently came across a piece of c code:(both a and b are integers) >printf("%d"+(a),b); >in passes compiler without any problem, what does this code mean ? "%d" evaluates to a POINTER to a char, i.e., char *. It is legal to add an integer to a pointer, so if one assumes that (a) represents an integer value, this would pass the value of the pointer, offset by the value of the integer expression a, as the first parameter of the printf call. God alone knows WHY anyone would want to do that, but, yes, it does appear to be legal C. Fred
chris@mimsy.umd.edu (Chris Torek) (10/22/89)
>In article <28255@iuvax.cs.indiana.edu> bobmon@iuvax.cs.indiana.edu >(RAMontante) writes: >>Henry Spencer and Chris Torek both tackle [printf("%d"+(a),b);] ... >>... and the winner is --- CHRIS TOREK, by a score of 148 to 12!!! >>(lines of response, that is) :-) In article <1989Oct21.234146.23275@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >In fairness, Chris gave a much more detailed and precise discussion of >the possible uncertainties in the interpretation of the code fragment. Actually, what I intended to do (with unknown success) was encourage people to think instead of just posting. To that end, I posted something outlining one way to think about the problem. There has been, and no doubt will continue to be, a rash of postings of the form `what does <x> do' for some simple but unusual <x> in programming language <y>. Most such questions are best answered by looking in a good book about <y>, or in the standard for <y>. (The previous round was about e1[e2], in the form i[a] instead of a[i].) -- `They were supposed to be green.' In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (10/23/89)
In article <543@uwm.edu>, zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: | I recently came across a piece of c code:(both a and b are integers) | printf("%d"+(a),b); | in passes compiler without any problem, what does this code mean ? I have no idea what it means, I can explain what it does... "%d"+a is a form of address plus integer expression notation. It evaluates to the *address* of the a'th character in the format. It also could be written as &("%d"[a]) if you wish. I have no idea why anyone would do this, and if a ever has a value other than zero or one when this executes it will be non-portable. For a==0 the value of b will be printed, while for a==1 the character d will be printed. This is either a typo or some really obscure C. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
t-wader@microsoft.UUCP (Wade Richards) (10/24/89)
In article <543@uwm.edu> zhao@csd4.csd.uwm.edu (T.C. Zhao) writes: =}I recently came across a piece of c code:(both a and b are integers) =}printf("%d"+(a),b); =}in passes compiler without any problem, what does this code mean ? =} =}-- =}---------------------------------------------- =}Internet: zhao@csd4.csd.uwm.edu =} BITNET: zhao%csd4.csd.uwm.edu@WISCMAC3.BITNET That code is the same as: switch( a ) { case 0: printf( "%d", b ); break; case 1: printf( "d", b ); break; case 2: printf( "", b ); break; default: printf( (char *)random(), b ); break; } The expression "%d"+(a) evaluates to a pointer to the string "%d\0" somewhere in memory, plus the integer a. The sum of a "pointer to type X" and an integer is another "pointer to type X", pointing to the a-th following object of type X. This is not at all clear. By way of example, if the pointer pointed to memory location 1000, and an object of type X took up 5 bytes, then the pointer plus 2 would be: 1000 + 2*5 = 1010. Hope this helps. --- Wade BYW, the (char *)random() simply means a (lot likely valid) pointer to anywhere.
haggas@kean.mun.ca (11/20/89)
The expression: printf("%03.0f", num); where num is a floating point number of three digits or less, eg 007 will not pad with zeros a right justified number of less than 3 digits, with Microsoft Optimizing Compiler V5.1. This expression will, however, work on a VAX 1187 using the UNIX "C" compiler. Padded zeros will be inserted if the number is an integer with the 5.1 compiler. The microcomputer is a NEC PowerMate '386, equiped with a 80287 co- processor. The Microsoft manual states in the printf() library reference that if the width argument is prefixed with a zero, the output, that is less than the specified with, will be padded zeroes. Has anyone experienced this problem and resolved it?
chris@mimsy.umd.edu (Chris Torek) (05/02/90)
>Chip Salzenberg <chip%tct@ateng.com> gripes: >>Aargh! Why do people use 'printf("%s", s)' when 'fputs(s, stdout)' is >>faster on every C implementation known to humankind? Gerkghd... In article <E4?05k7@cs.psu.edu> flee@shire.cs.psu.edu (Felix Lee) writes: >Hmm. Isn't fputs slower in some generation of BSD? In fact, I'm >pretty sure of it. In 4.1 and 4.2 BSD, yes (and previous releases as well). The old fputs() code was, in essence, while ((c = *ptr++) != 0) if (putc(c, outf) == EOF) return EOF; return 0; Since there are three (count 'em three :-/ ) different kinds of output buffering, and since the C compiler could not tell that putc()---which expanded to a horrible ?: expression including a call to _flsbuf()--- did not generally switch among them, this expanded to long and slow code paths. >The last time I looked at fputs it used putc wrapped in a while loop, >which is a lot of needless work inside the loop---using strlen and >fwrite is almost certainly faster. Unfortunately, in those same implementations fwrite() itself was just another loop around putc(). This Has Been Fixed (whether in 4.3BSD or only in 4.3-tahoe, I cannot recall). >And _doprnt (printf) on the VAX is hand-coded assembly that avoids the >needless work. Well, I think it does; I never looked at it closely. I did; it does, and it does not. It was not terribly well coded, but it did move characters generally more efficiently than did the old fputs and fwrite. >Anyway, an optimal printf("%s",s) is maybe a dozen more machine >instructions than an optimal fputs(s,stdout). Unless you're printing >thousands of strings, I can't see it making a significant difference. >But then, I doubt that anyone has an optimal stdio library . . . I am trying. I think I am getting there. printf() will still be a fair amount slower, however. Among other things, fputs expands to the sequence call strlen. set up single output vector. call __sfvwrite: if nothing to write, return early. check to make sure this stream can be written; if not, return an error. if unbuffered: for each vector, write it. if fully buffered: for each vector, append it to the partly-full buffer, or write one block directly, or put the remaining less-than-a-block into the buffer, whichever applies best; write the buffer as necessary when it becomes full. if line buffered: for each vector, act as on fully buffered files, but stop at newlines and do fflush() as necessary to cause complete lines to get emitted as they occur. return any error code. return any error code. while printf("%s") now expands to the sequence set up varargs stuff. call vfprintf: check to make sure this stream can be written. check to see if this is an unbuffered Unix output stream, in which case it should be `optimised' (via a secondary function that uses a temporary buffer); here it is not. set up return value and io vector information. examine format, note %, stop examining format. make a vector out of any text leading up to the % (here none, hence no vector). set defaults for precision, field width, etc. switch on format, case is 's'. undo any sign flag ("%+s" should not print a sign). check precision; since it is unspecified, call strlen (if precision given, call memchr instead). break from case (go to common field-output code). check for prefixes (sign, leading blanks or 0s, etc), setting up output vectors for them (none here). set up output vector for the field itself. check for suffixes (trailing zeros/blanks/etc), setting up output vectors for them (none here). call __sprint: call __sfvwrite: __sfvwrite acts just as before. reset io vector information. return any error indication. if error, stop (but no error here). examine format, note '\0', stop examining format. make a vector out of any text between the last %s and this point (here none, hence no vector). since there are no vectors, do not bother with sprint. return the number of characters written. return what vfprintf returned. (At a minimum, this seems like `about sixteen more things' than necessary in fputs()---a bit more than Felix's 12, anyway.) vfprintf() is a terribly complicated function, what with all the different formats and flags allowed. (And people complain that it does not do enough! If your printf correctly handles formats like "%#0-1000g" and "%.400f", consider yourself lucky.) All the `io vector' goo above is a great simplification of the previous mess (even if it does involve testing for newlines that can be guaranteed not to be present---this could perhaps be improved). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
scs@athena.mit.edu (Steve Summit) (05/04/90)
In article <26387BCF.390@tct.uucp> chip@tct.uucp (Chip Salzenberg) writes: >Aargh! Why do people use 'printf("%s", s)' when 'fputs(s, stdout)' is >faster on every C implementation known to humankind? I always use printf. I even use printf("\n") when putchar('\n') would "obviously" be better. The reason is the consistency factor several people have already mentioned, but it's more than just abstract warm fuzzies. Many times I have been extremely glad to be able to do global substitutions of "printf(" with "fprintf(fd, " or "printf" with "output" or something similar, and know that I've gotten everything without having to go back and take care of puts's or putchar's by hand. Even in a critical section where efficiency might matter, the underlying physical I/O overhead often swamps any extra CPU time that a "less efficient" path through stdio might introduce. Steve Summit scs@adam.mit.edu
melling@cs.psu.edu (Michael D Mellinger) (05/29/91)
Is there a way to print numbers less than 10^-4 in decimal notation without trailing zeros? For example, I want printf("%g\n", .000010) to be printed as .00001. %g uses the %e format if numbers are less than 10^-4. -Mike