[comp.lang.c] printf

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