[comp.lang.c] Don't use Scanf

knudsen@ihwpt.ATT.COM (mike knudsen) (03/01/88)

Don't use Scanf() from the C Standard Library if you care
about the size of your object program.  It uses 5K
(yes, 5000 bytes) of text space, plus over 200 bytes of Data.
Ripping it out of my huge music editor really opened things
up for new features this weekend.
[Above figures are for Microware OS9 6809 C library].

It's well worth writing your own code to do simple parses.
Among the string functions, try Index(char, string) which
will find commas and such in the input.
Input is best got from gets(string).

Besides, scanf() has always been hostile to users who don't
type in just the right stuff.  If you need it for user-friendly
stuff use gets(string) followed by sscanf(string).

Note: "string" means "(char *)" or "char[]" in the above.
PS: Printf() is probably just as big, but usually harder to
do without, especially in a big program.
-- 
Mike J Knudsen    ...ihnp4!ihwpt!knudsen  Bell Labs(AT&T)
    Delphi: RAGTIMER    CIS: <memory failure, too many digits>
	"Just say NO to MS-DOS!"	"OS/2 == 1/2 of an OS"

johnson@c10sd1.StPaul.NCR.COM (Wayne D. T. Johnson) (03/05/88)

In article <2401@ihwpt.ATT.COM> knudsen@ihwpt.ATT.COM (mike knudsen) writes:
>Don't use Scanf() from the C Standard Library if you care
>about the size of your object program.  It uses 5K
>(yes, 5000 bytes) of text space, plus over 200 bytes of Data.
>Ripping it out of my huge music editor really opened things
>up for new features this weekend.

I've also noticed that printf is somwhat bulky.  If you know what you
are going to print out, why not print it out your self instead of
using a (simple) interpreter to do it for you.

Real programmers don't use printf ;-)

rk9005@cca.ucsf.edu (Roland McGrath) (03/11/88)

One real stupidity I've seen many, many times is the
over-use of printf.  The printf functions have their uses,
and they do their job quite well, but please know what these
uses are!!

For example:
	printf("Hello world!\n");
Haven't you ever heard of puts????
	puts("Hello world!");	/* note the newline is appended	*/
or
	printf("hi");
try fputs:
	fputs("hi", stdout);	/* no newline appended	*/
What's that?  Oh, now you have to include <stdio.h> so
you can get the proper declarations of all these functions anyway?
Poor baby!

And the ultimate stupidity:
	printf("\n");
Get a brain!!!!!  You're using the function that can do complex
data formatted output to write one bleeping character!!!!!
Try
	putchar('\n');
If you include <stdio.h>, this will probably end up being a macro
that will write it out very fast.

I have even seen:
	sprintf(buf, "constant string");
Hey, Mr. Power-Programmer, ever heard of strcpy????


In general, if there's no format spec, don't use printf!!!!!!
-- 
	Roland McGrath
ARPA: roland@rtsg.lbl.gov roland@lbl-rtsg.arpa
UUCP: ...!ucbvax!lbl-rtsg.arpa!roland

pete@wlbr.EATON.COM (Pete Lyall) (03/12/88)

In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
>One real stupidity I've seen many, many times is the
>over-use of printf.  
>
>For example:
>	printf("Hello world!\n");
>Haven't you ever heard of puts????
>	puts("Hello world!");	/* note the newline is appended	*/

Hmmmm. What about the case where 'printf()' is already used elsewhere
in the program for argument substitution and formatting? Wouldn't
this merely be just another subroutine (in RMA) call to the already
included 'printf' function? If that is in fact the case, the I would
suspect that the use of 'puts()' or 'fputs()' would actually add code,
unless of course the 'puts()' or 'fputs()' are used internally by
'printf()'. I doubt that this is the case (my local unix.wizard says
the 'puts' brothers aren't used by 'printf()', at least not here).

Another item you might consider... if you're using a coco3 under level
II, the minimum allocation segment is 8k under the memory management
scheme. Os9 doesn't care if the program is 79 bytes or 7900 bytes, it
is still going to allocate 8192 for the program segment (or some
multiple thereof). Of course the counter arguments are that if you're
byte-fighting to get within the next lower 8k notch, removal of *all*
printf's may do you some good (approximately 3-5k).  Also, you could
save some disk space by removing *all* printf's.


-- 
Pete Lyall (OS9 Users Group VP)|  DELPHI: OS9UGVP  |  Eaton Corp.(818)-706-5693
Compuserve: 76703,4230 (OS9 Sysop) OS9 (home): (805)-985-0632 (24hr./1200 baud)
Internet: pete@wlbr.eaton.com      UUCP: {ihnp4,scgvax,jplgodo,voder}!wlbr!pete 

knudsen@ihwpt.ATT.COM (mike knudsen) (03/12/88)

Good points.  But if you already are using printf() in your
program (with a legitimate need for the formatting) in several
places, then substituting puts() where possible will make
your program object file bigger, not smaller, since
now the puts() code has to be linked in too.
Puts() and putchar() will be a little faster, but when you're
talking to humans who cares?

BTW, I once wrote a large interactive monitor for a free-standing
8086 board, using a C that had no I/O at all.  I wrote routines
to output %2x, %4x, and %5d as well as strings.
Took a lot of calls to do one good printf(),
but it IS possible and such custom I/O may save you bytes.
-- 
Mike J Knudsen    ...ihnp4!ihwpt!knudsen  Bell Labs(AT&T)
    Delphi: RAGTIMER    CIS: <memory failure, too many digits>
	"Just say NO to MS-DOS!"	"OS/2 == 1/2 of an OS"

ugfailau@sunybcs.uucp (Fai Lau) (03/12/88)

In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
>One real stupidity I've seen many, many times is the
>over-use of printf.  The printf functions have their uses,
>and they do their job quite well, but please know what these
>uses are!!

	C'mon!!! Is it really an issue?

>For example:
>	printf("Hello world!\n");
>Haven't you ever heard of puts????
>	puts("Hello world!");	/* note the newline is appended	*/

	I can't imagine any reasonably competant C compiler not
generating the almost same codes for both cases.

>or
>	printf("hi");
>try fputs:
>	fputs("hi", stdout);	/* no newline appended	*/
>What's that?  Oh, now you have to include <stdio.h> so
>you can get the proper declarations of all these functions anyway?
>Poor baby!

	<stdio.h> should be included in mostly every program
just so that when you do need it you have it around. It's not
gonna give you a bigger or slower program.

>And the ultimate stupidity:
>	printf("\n");
>Get a brain!!!!!  You're using the function that can do complex
>data formatted output to write one bleeping character!!!!!
>Try
>	putchar('\n');
>If you include <stdio.h>, this will probably end up being a macro
>that will write it out very fast.
>
>I have even seen:
>	sprintf(buf, "constant string");
>Hey, Mr. Power-Programmer, ever heard of strcpy????

	Let's face it. The best way to give efficiency to a program
is to write your own macro to handle file I/O and strings. Macros like
strcpy are too general if you want to be picky. 
	For example, if you want to print a string fast, you would write
a routine that uses only putc with no format capacity and no error
checking whatsoever, and forget about printf. Most of what you
said are true. But if one has to be as picky as you suggest, then
let's forget about stdio.h and strings.h and write everything from
the ground up.

Fai Lau
SUNY at Buffalo (The Arctic Wonderland)
UU: ..{rutgers,ames}!sunybcs!ugfailau
BI: ugfailau@sunybcs INT: ugfailau@joey.cs.buffalo.EDU

jv@mhres.mh.nl (Johan Vromans) (03/12/88)

In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
>One real stupidity I've seen many, many times is the
>over-use of printf.  The printf functions have their uses,
>and they do their job quite well, but please know what these
>uses are!!
>
> [examples of using puts, fput, putc instead of printf]
>
>And the ultimate stupidity:
>	printf("\n");
>Get a brain!!!!!  You're using the function that can do complex
>data formatted output to write one bleeping character!!!!!
>Try
>	putchar('\n');
>If you include <stdio.h>, this will probably end up being a macro
... If you don't you will likely end up with a missing routine ...
>that will write it out very fast.

Yes. But it does not flush if the output is a terminal or line-buffered.

>In general, if there's no format spec, don't use printf!!!!!!

I partly agree. When you are short on space, and want to eliminate the use
of "large" routines like printf, you are right.
On the other hand, you suggest the use of four or five different routines
(with all different calling sequences) instead of one simple and elegant
"printf" routine. Printf *CAN* do complex formatting, but it *DOESN'T* do
this if you don't have format strings. What remains is just the tiny
overhead of testing whether there are formatting characters in the string...

I dislike discussions in which the quality of the arguments is measured by the
number of exclamation marks following each sentence.


-- 
Johan Vromans                              | jv@mh.nl via European backbone
Multihouse N.V., Gouda, the Netherlands    | uucp: ..{uunet!}mcvax!mh.nl!jv
"It is better to light a candle than to curse the darkness"

henry@utzoo.uucp (Henry Spencer) (03/13/88)

> 	For example, if you want to print a string fast, you would write
> a routine that uses only putc...

!!NO!!  If you want to print a string fast, you use fputs and insist that
your supplier implements it properly.  Putc has to do things like buffer-
overflow checking on every character; a fast implementation of fputs can
inspect the buffer *once*, note that there is room for N more characters,
copy N characters at high speed, and then update counts and so forth *once*.
This is a major efficiency win over putc if you are doing it a lot.

Unfortunately, not all implementors make the effort to make stdio fast.
In general, System V stdios are fast and 4BSD ones are not.  (There are
exceptions to this, both ways, and I believe the 4BSD one is going to be
improved.)
-- 
Those who do not understand Unix are |  Henry Spencer @ U of Toronto Zoology
condemned to reinvent it, poorly.    | {allegra,ihnp4,decvax,utai}!utzoo!henry

sef@csun.UUCP (Sean Fagan) (03/13/88)

In article <9241@sunybcs.UUCP> ugfailau@sunybcs.UUCP (Fai Lau) writes:
>In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
[regarding uses of printf(3)]

>	C'mon!!! Is it really an issue?

Yes, it can be; since printf(3) is interpreted, it *WILL* be slower than
directly coding the correct statements.  I.e., printf("Hello world!\n") is
slower than puts("Hello world!") which is slower than 
write(1,"Hello world!\n",13).  If you're doing a lot of I/O like this, it can
be significantly slower.

>>For example: [printf vs. puts]
>	I can't imagine any reasonably competant C compiler not
>generating the almost same codes for both cases.

What does a compiler have to do with a *subroutine*?!  printf is a
subroutine, just like any other; the compiler knows nothing about it, nor
should it.  (As an aside, I've thought about writing a printf compiler, but
has anybody else already done that?  The generated code would be larger,
but, most likely, quite a bit faster...)

>	<stdio.h> should be included in mostly every program
>just so that when you do need it you have it around. It's not
>gonna give you a bigger or slower program.

No, but it does eat up namespace, typedef space, you're precluded from using
your own putc, getc, etc., etc.

>>And the ultimate stupidity:
>>	printf("\n");
>>Get a brain!!!!!  You're using the function that can do complex
>>data formatted output to write one bleeping character!!!!!
>>Try
>>	putchar('\n');
>>If you include <stdio.h>, this will probably end up being a macro
>>that will write it out very fast.
[sprintf(buf, "constant string"); instead of strcpy]
>	Let's face it. The best way to give efficiency to a program
>is to write your own macro to handle file I/O and strings. Macros like
>strcpy are too general if you want to be picky. 
[write own routine using putc for fast I/O]

No, if one wants to do that, one doesn't use <stdio> at all; one uses
write(2) (assuming you're on Unix; however, most PC C compilers support
write anyway).  For the most part, I don't include <stdio> in my programs at
all; printf doesn't need it, and I can get by with write very easily.

>Fai Lau
>SUNY at Buffalo (The Arctic Wonderland)
>UU: ..{rutgers,ames}!sunybcs!ugfailau
>BI: ugfailau@sunybcs INT: ugfailau@joey.cs.buffalo.EDU


-- 

Sean Fagan                   uucp:   {ihnp4,hplabs,psivax}!csun!sef
CSUN Computer Center         BITNET: 1GTLSEF@CALSTATE
Northridge, CA 91330         (818) 885-2790

belmonte@svax.cs.cornell.edu (Matthew Belmonte) (03/13/88)

In article <9241@sunybcs.UUCP> ugfailau@sunybcs.UUCP (Fai Lau) writes:
>	C'mon!!! Is it really an issue?

It shouldn't be.  This discussion reminds me of a time a few years ago when I
was living near Washington, D.C. and someone on a local BBS decried the use of
comments in source code because they increase compilation time.

>In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
>>For example:
>>	printf("Hello world!\n");
>>Haven't you ever heard of puts????
>>	puts("Hello world!");	/* note the newline is appended	*/
>
>	I can't imagine any reasonably competant [sic] C compiler not
>generating the almost same codes for both cases.

Imagine again.  The generated code will be a push of the address of the argument
(in the above examples, a constant string) onto the stack, followed by a
jump-to-subroutine to the called function, either _printf or _puts.  Thus, the
object codes are completely disparate.  But this doesn't alter the fact that
IT JUST DOESN'T MAKE ENOUGH DIFFERENCE FOR THE PROGRAMMER TO CARE.  printf and
puts are both linear-time algorithms.  printf probably takes a little longer
because it has to check for embedded format strings, but it doesn't find any in
this case, so the extra time is negligible.  As for the space, someone already
mentioned that the effect of chopping out library routines such as _printf is
usually swamped by the effect of the operating system's block allocation scheme.
Program images take constant space.  It's only the data space that can get
larger with problem size, and that's what you should be concerning yourselves
with.

There are some things worth devoting your time to, and there are other things
better left alone.  These are sometimes difficult to differentiate, but not in
this case.  YOU PEOPLE ARE NITPICKING.
-- 
Matthew Belmonte
Internet:	belmonte@sleepy.cs.cornell.edu
BITNET:		belmonte@CRNLCS
*** The Knights of Batman ***
(Computer science 1, College 5, Johns Hopkins CTY Lancaster '87 session 1)

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (03/14/88)

In article <2057@svax.cs.cornell.edu>, belmonte@svax.cs.cornell.edu (Matthew Belmonte) writes:
> 
> Imagine again.  The generated code will be a push of the address of the argument

> But this doesn't alter the fact that
> IT JUST DOESN'T MAKE ENOUGH DIFFERENCE FOR THE PROGRAMMER TO CARE.  printf and
> puts are both linear-time algorithms.  printf probably takes a little longer
> because it has to check for embedded format strings, but it doesn't find any in
> this case, so the extra time is negligible.

   I've tried staying out of this STUPID conversation but .....

   It all depends.  One of the routines I've written was a database
dump facility.  The object was to dump the entire contents of the
database in some human readable format and later to be able to
parse the dump file and reload the database.  Anyway, I was
looking for ways to decrease the dump time and one of the things
I did was to replace calls to fprintf on unformatted strings with calls
to a routine that printed just a string using putc.  In doing this I was
able to get about a 20% increase in speed.  Not too much, but for what
took all of an hour to do, I would say a reasonable investment.

  In general however your comments stands.  


BTW: Dicky Moe, if you don't want people replying to your articles,
don't bother posting them on the net.  Followups to /dev/null annoys the hell
out of me!


-- 

Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

ccs6277@ritcv.UUCP (Cliff SKolnick) (03/14/88)

About this printf issue.  If you look at the Newsgroups line, you'll see
comp.sys.m6809, that is where this discussion started.  This is <64K
code machine.  If they are talking about a CoCo usualy <720K of disk space
too.  Size I believe was the issue.

kim@mcrware.UUCP (Kim Kempf) (03/15/88)

In article <9241@sunybcs.UUCP>, ugfailau@sunybcs.uucp (Fai Lau) writes:
>In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
>>One real stupidity I've seen many, many times is the
>>...
>
>	C'mon!!! Is it really an issue?
>
>>For example:
>>	printf("Hello world!\n");
>
>	I can't imagine any reasonably competant C compiler not
>generating the almost same codes for both cases.
>
The issue here is not the code the compiler generates (its the same in
either case) but the execution time expended.  Given an arbitrary string
to output, printf must look at each character checking for a '%' for
format conversion.  If no format conversions are desired, its much faster
to use puts().  Furthermore, if the conversion string *does* contain
a '%' and is not escaped, watch out!  Consider the following:

	printf("It's 100%unusable!\n");

The output is unexpected at best.

johnson@c10sd1.StPaul.NCR.COM (Wayne D. T. Johnson) (03/15/88)

In article <2428@ihwpt.ATT.COM> knudsen@ihwpt.ATT.COM (mike knudsen) writes:
>Good points.  But if you already are using printf() in your
>program (with a legitimate need for the formatting) in several
>places, then substituting puts() where possible will make
>your program object file bigger, not smaller, since
>now the puts() code has to be linked in too.
>Puts() and putchar() will be a little faster, but when you're
>talking to humans who cares?
>

Puts and putchar may seem to be only a little faster to humans only
until you use packages that do windowing and full page menus, or even
redirect your output to disk (ever write out 3.5 meg using a printf?).
besides, memory is cheap and getting cheaper but CPU time is still costing
quite a bit.

In several instances I have found that removing several printf's that
were in critical paths of our code has remarkable speeded things up.
        -Wayne

g-rh@cca.CCA.COM (Richard Harter) (03/15/88)

Re: Should one use puts versus always using printf.

Some years ago someone (I don't have a reference anymore) took a
fortran compiler and modified it to compile formatted writes rather
than interpreting them.  The gains in execution time were modest, on
the order of 1-2%, at best.  Corresponding gains can be expected in
C.  While it is true that using puts rather than printf when applicable
is faster, the execution time efficiency gained is not particularly
important.

As a matter of programming style, it is preferable (all other things
being equal) to use a single standard mechanism rather than a variety
of mechanisms.  It makes programs more complicated to write, maintain,
and read if a variety of mechanisms are used for the same function.
This is a simplicity versus execution time tradeoff.

In our situation (SMDS not CCA) portability is an issue.  By policy we
restrict the use of library routines to a minimum -- the only library
functions which are not carefully isolated are printf and fprintf.  If
I don't use puts() I don't have to know whether it runs the same and
interacts the same with printf() on all machines and operating systems
that we deal with.  This policy is reasonable for out situation; it is
not necessarily relevant for others.

I would also note that if execution time for I/O is truly a concern
(and it sometimes is) then one should look at doing formatting by hand,
i.e. building output lines directly and writing whole lines only.

In summary, this is one of those little efficiencies that is not worth
bothering about in most applications.
-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

karl@haddock.ISC.COM (Karl Heuer) (03/16/88)

In article <1140@csun.UUCP> sef@csun.UUCP (Sean Fagan) writes:
>printf("Hello world!\n") is slower than puts("Hello world!") which is slower
>than write(1,"Hello world!\n",13).

Using write() instead of the stdio routines is not necessarily a win, because
non-UNIX systems may still have to fiddle with e.g. NL vs. CRLF conversions.
Also note that (even on UNIX) the buffering which is usually done in stdio may
let you write everything with a single system call; this can make stdio faster
than multiple calls to write().

>For the most part, I don't include <stdio> in my programs at all; printf
>doesn't need it, and I can get by with write very easily.

I once used a compiler that let me use stdin, stdout, stderr without including
<stdio.h>.  I included it anyway, because I knew that omitting it was not
portable.  If your implementation lets you use printf without <stdio.h>, fine,
but don't complain too loudly if you try to port your code and it suddenly
stops working.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

djones@megatest.UUCP (Dave Jones) (03/16/88)

> In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
..
>>And the ultimate stupidity:
>>	printf("\n");
>>Get a brain!!!!!  You're using the function that can do complex
>>data formatted output to write one bleeping character!!!!!

I've done this before.  And I have a brain.  Although I sometimes use
its complex data processing function to write silly little responses to
silly postings.

I think I should point out that you are mistaken about this being
the ultimate stupidity.  The actual ultimate stupidity -- and you could
look this up -- is microwave popcorn.

I hope this clears the matter up satisfactorily,

		Dave Jones
		880 Fox Lane
		San Jose, CA.
		95131

		(408) 437-9700 Ext 3227
		UUCP: ucbvax!sun!megatest!djones
		ARPA: megatest!djones@riacs.ARPA

wynkoop@esquire.UUCP (Brett Wynkoop) (03/17/88)

Greeting folks-
     Just remember that this discussion started as a discussion of C under
os9 on 6809 microprocessors.  In many cases these boxes just have 64k of
memory, and a huge 360k to 720k of disk space which must hold the os, the
compiler, and all data files. This means that the discussions about C under
Unix may not be very relevent to this newsgroup.


ALL FLAMES TO /DEV/NULL on Unix boxes
ALL FLAMES TO /NILL on OS9 boxes


-Brett

---------------------------------------------------------------------------

...........rutgers!cmcl2!esquire!wynkoop
CIS........72057,3720
data.......212-942-0846 300,1200,2400 8n1
voice......212-266-0741

===========================================================================
	       "Character is what you are in the dark"
					     -Lord John Warfin

---------------------------------------------------------------------------

belmonte@svax.cs.cornell.edu (Matthew Belmonte) (03/17/88)

In article <46.bagpiper@oxy.UUCP> bagpiper@oxy.uucp writes:
[on the subject of printf and puts, and all the other library goodies:]
>These are not part of the language!!  They are some external routine.  The
>compiler can`t do this kind of optimization.

Well, not exactly.  It is possible to get the compiler to do such an
optimisation; it wouldn't be hard.  Consider the following snatch of an
attribute grammar:

expr ::= ident '(' args ')' {
	.
	. /*there is a lot of code here that does other things*/
	.
	. /*now, here's the part where we're about to emit a symbol for the
	    printf call:*/
	   fprintf(outfile, "lbsr %s /*call the subroutine*/\n",
	      $3.is_const && TypesEqual($3.type, STRING) ? "_puts" : "_printf");
	.
	.
	. }
	;
args ::= args arg {
	.
	. /*there's code here to shove the argument onto the stack*/
	$$.is_const = false; }
    | arg {
	$$.is_const = $1.is_const;
	$$.type = $1.type; }
	;

The .type and .is_const attributes are propagated up from the expressions which
constitute the arguments.  So, it wouldn't be much of a job to hack something
like this in, if you were given the source for an existing C compiler.  BUT...
Mods like this can be more of a pain in the ass than they are a help.  Here the
programmer has no control over what library routines will end up included in his
object.  This compiler is fickle, and that's BAD.
-- 
Matthew Belmonte
Internet:	belmonte@sleepy.cs.cornell.edu
BITNET:		belmonte@CRNLCS
*** The Knights of Batman ***
(Computer science 1, College 5, Johns Hopkins CTY Lancaster '87 session 1)

richard@aiva.ed.ac.uk (Richard Tobin) (03/18/88)

In article <1140@csun.UUCP> sef@csun.UUCP (Sean Fagan) writes:
>Yes, it can be; since printf(3) is interpreted, it *WILL* be slower than
>directly coding the correct statements.  I.e., printf("Hello world!\n") is
>slower than puts("Hello world!") which is slower than 
>write(1,"Hello world!\n",13).  If you're doing a lot of I/O like this, it can
>be significantly slower.

The key phrase here is "If you're doing a lot of I/O like this".  You would
certainly have to execute this statement a large number of times for the
interpretation to take longer than counting the characters in the string
(maybe I just don't count fast :-).

The computer's time is much less valuable than mine (to me, at least), so
except in very rare circumstances I'm not going to think about how hard it
is for the computer.  I'm quite happy to put 'printf("\n")' in my programs,
especially when it's surrounded by other calls to printf.

Of course, printf() vs write() is also a portability question, but I'm sure
there will be plenty of comments on that...

-- Richard
-- 
Richard Tobin,                         JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,             ARPA:  R.Tobin%uk.ac.ed@nss.cs.ucl.ac.uk
Edinburgh University.                  UUCP:  ...!ukc!ed.ac.uk!R.Tobin

tp@td2cad.intel.com (t patterson) (03/18/88)

In article <2980@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <1140@csun.UUCP> sef@csun.UUCP (Sean Fagan) writes:
>>printf("Hello world!\n") is slower than puts("Hello world!") which is slower
>>than write(1,"Hello world!\n",13).
>
>Using write() instead of the stdio routines is not necessarily a win, because
>non-UNIX systems may still have to fiddle with e.g. NL vs. CRLF conversions.
>Also note that (even on UNIX) the buffering which is usually done in stdio may
>let you write everything with a single system call; this can make stdio faster
>than multiple calls to write().

   for those of you arguing about the relative merits of printf,
puts, and write, here's some times for each of the three writing 
"hello world\n" to /dev/null 100,000 times on a uVAX II running Ultrix 2.0:

printf		18 sec		(wall-clock time, not user or sys time)
puts		15 sec
write		59 sec

following is a script of what I did (with white space added), then the
source of the three test programs. such a simple test doesn't say a 
whole lot. decide for yourself what it means.

Script started on Thu Mar 17 13:11:17 1988
ctdone> time tprintf >/dev/null
17.3u 0.5s 0:18 98% 7+21k 0+0io 0pf+0w

ctdone> time tputs >/dev/null
14.6u 0.4s 0:15 99% 4+21k 0+0io 0pf+0w

ctdone> time twrite >/dev/null
5.1u 53.4s 0:59 98% 1+3k 0+0io 0pf+0w

ctdone> time tprintf >/usr/tmp/t
17.4u 1.9s 0:19 98% 7+21k 5+154io 0pf+0w

ctdone> time tputs >/usr/tmp/t
14.8u 1.9s 0:17 97% 3+21k 6+155io 0pf+0w

ctdone> time twrite >/usr/tmp/t
4.7u 346.4s 6:02 96% 1+3k 7+192io 0pf+0w

ctdone> 
script done on Thu Mar 17 13:23:56 1988

tprintf.c:
	main() 
	{
		int i;
	
		for ( i = 100000; i > 0 ; i-- ) {
			printf("hello world\n");
		}
		exit(0);
	}

tputs.c:
	main()
	{
		int i;
	
		for ( i = 100000; i > 0 ; i-- ) {
			puts("hello world");
		}
		exit(0);
	}

twrite.c:
	main()
	{
		int i;
	
		for ( i = 100000; i > 0 ; i-- ) {
			write(1, "hello world\n", 12);
		}
		exit(0);
	}
--
  ..tp.. t patterson	domain:	tp%td2cad.intel.com@relay.cs.net
			path:   {ihnp4,cbosgd,uunet}!wucs1!tp
                  		{pyramid,hoptoad}!td2cad!tp
                  		{decwrl,hplabs,oliveb}!intelca!mipos3!td2cad!tp

gwyn@brl-smoke.ARPA (Doug Gwyn ) (03/19/88)

In article <1140@csun.UUCP> sef@csun.UUCP (Sean Fagan) writes:
>For the most part, I don't include <stdio> in my programs at
>all; printf doesn't need it, and I can get by with write very easily.

printf() most certainly does need <stdio.h> included to correctly
declare its type, in general; if you haven't gotten into trouble
by not having a variadic declaration in scope, it's only because
you've been using implementations on relatively simple architectures.

write(1,...) is not at all standard, so if you're trying to write
portable applications you should stick with the standard library.

You should also realize that in most cases it is more important for
the source code to be maintainable that to squeeze the last bit of
performance out of the hardware.  This lesson was learned by most
professionals in the late 1960s and early 1970s.

Finally, your intuitions about what is "efficient" are wrong.  I
ran a test that simply printed "Hello, world!\n" 100,000 times on
the standard output, on a Gould PN9080 using my SVR2 emulation,
which has essentially the UNIX System V stdio implementation.  I
tried it three ways, using printf, fputs to stdout, and write to
file descriptor 1 (in all cases using /dev/null as the output file).
Here are the results:

	printf	 5.5 seconds (user + system)
	fputs	 4.0 seconds (user + system)
	write	14.2 seconds (user + system)

You do gain a little by using fputs, although in a normal application
(rather than an output test program) the difference would be not be
significant.  Note that write(1,...) is a major lossage since you lose
buffering.

g-rh@cca.CCA.COM (Richard Harter) (03/20/88)

In article <296@aiva.ed.ac.uk> richard@uk.ac.ed.aiva (Richard Tobin) writes:

>Of course, printf() vs write() is also a portability question, but I'm sure
>there will be plenty of comments on that...

Since you asked :-).  People who mix printf and write are likely to be
visited by things from Binkley's anxiety closet when they leave the safe
haven of UNIX.  If your software is going to run under any operating 
system other than UNIX, don't even think about doing this!

Paranthetically, it is good practice to gather all of your fopens, opens,
etc, together in a few well defined places in portable code.  Life will
be much simpler if you do.  [It may be best to use standardized macros
which are machine dependent, but I've never made the effort to do.  If
anyone has worked these out for VMS, UNIX, and PRIMOS and posts them, I
will bless them.]
-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

aglew@ccvaxa.UUCP (03/21/88)

>One real stupidity I've seen many, many times is the
>over-use of printf.  The printf functions have their uses,
>and they do their job quite well, but please know what these
>uses are!!

It would be nice if compilers could do a bit of processing,
determine that printf("string with no formats") can be transformed
into puts -- so that we can get on with the important job of solving
problems, and not have to play games remembering which I/O function
to use today (well, tcputs() is almost what I need, but its 
buffering conflicts with fooprintf() which is implicitly used
by the error printing routine used in module xyzzy).

henkbo@philce.UUCP (Henk Boetzkes) (03/21/88)

How reliable are the tprintf_tputs_twrite test ???
I just add two test more to your output.

"hello world\n" to /dev/null 100,000 times on a uVAX II running Ultrix 2.0:

printf		18 sec		(wall-clock time, not user or sys time)
puts		15 sec
write		59 sec

"hello world\n" to /dev/null 100,000 times on a VAX11/780  running Ultrix 2.0:

printf		20 sec	
puts		14 sec
write		57 sec

"hello world\n" to /dev/null 100,000 times on a SUN/280  running SUN 3.5:

printf		 4 sec	
puts		 4 sec
write		17 sec

gp@picuxa.UUCP (Greg Pasquariello X1190) (03/23/88)

In article <9241@sunybcs.UUCP>, ugfailau@sunybcs.UUCP writes:
> In article <1185@ucsfcca.ucsf.edu> roland@rtsg.lbl.gov (Roland McGrath) writes:
> >For example:
> >	printf("Hello world!\n");
> >Haven't you ever heard of puts????
> >	puts("Hello world!");	/* note the newline is appended	*/
> 
> 	I can't imagine any reasonably competant C compiler not
> generating the almost same codes for both cases.




	These are library calls, and although the compiler will generate
approximately the same function calling sequence, the linker will link in 
a much larger function in printf().



> 	Let's face it. The best way to give efficiency to a program
> is to write your own macro to handle file I/O and strings. Macros like
> strcpy are too general if you want to be picky. 
> 	For example, if you want to print a string fast, you would write
> a routine that uses only putc with no format capacity and no error
> checking whatsoever, and forget about printf. 




	That is about what puts() does!  However, rather than looping on
putc(), the string is put directly into the buffer with memcpy(), which is
quicker.


Greg Pasquariello
ihnp4!picuxa!gp

henry@utzoo.uucp (Henry Spencer) (03/24/88)

> Paranthetically, it is good practice to gather all of your fopens, opens,
> etc, together in a few well defined places in portable code...

This turns out to be a good idea for another reason:  if you seriously care
about good-quality error handling, it almost always needs to be customized
to your program to some extent, and things are much simpler if the error
handling for things like fopen is centralized.
-- 
"Noalias must go.  This is           |  Henry Spencer @ U of Toronto Zoology
non-negotiable."  --DMR              | {allegra,ihnp4,decvax,utai}!utzoo!henry

belmonte@svax.cs.cornell.edu (Matthew Belmonte) (03/31/88)

In article <960@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes:>
>Compilers do not have the ability to understand the functionality of the
>procedures being called and alter the code (and arguments!) accordingly!

What you mean to express by "understand the functionality" appears nebulous to
me.  As I said before, nothing practical prevents one from including the
semantics of standard functions in compilers.  Conversions from one sequence of
statements to another with equivalent semantics can be expressed using
attribute grammars.

>Apart from anything else, the "functionality" of printf and puts is only
>determined at *link* time!

Again, it is unclear to me what you mean by determination of "functionality."
It is true that in a typical compiler, the only optimisations done are
flow-of-control optimisations (e.g. induction variables reduction in strength,
live variable analysis, code motion) and computation and storage optimisations
(e.g. elimination of common subexpressions, copy propagation, constant folding,
register allocation) *within* the code being compiled.  Calls to external
functions  can be treated atomically, as "black boxes" -- but there's no rule
that says they *have* to be.  If a function is part of a standard library, then
rules can be included in the compiler for simplification of those functional
expressions.

To take a simple example, suppose I have a standard function called expt which
takes a floating-point argument and raises it to a power.  Suppose I have a
functional expression "expt(x, 2)".  So rather than calling in my high-powered
expt function it would be much simpler to do a floating-point multiply of x*x.
This is a reduction in strength which encompasses an invocation of a standard
function.  (Suppose I had an exponentiation operator "**" s.t. "x ** y" gives
the value of expt(x, y).  Then there would be no external function involved,
and everything would be straightforward.)

So *why* do we never see semantics of standard functions included in compilers?
Because, in my opinion, it's not worth it.  It makes the compiler dependent on
the standard libraries.  If my compiler's rules assume a particular
implementation of a standard function, then if I change the implementation I'm
liable to have either to change the compiler or to live with inefficient code.

In summary:  There is no inherent limitation of compilers which prevents their
knowing about standard functions.  Despite this, we never see compilers playing
with standard functions, because that would create too much of a tangled mess
of dependencies.  So Fai Lau was being unrealistic in saying that compilers
which don't do this sort of thing are unimaginable.  Yet at the same time, it
is wrong to assert, as Ray Dunn does, that such optimisations are impossible.

Comments are welcome.
-- 
Matthew Belmonte
Internet:	belmonte@sleepy.cs.cornell.edu
BITNET:		belmonte@CRNLCS
*** The Knights of Batman ***
(Computer science 1, College 5, Johns Hopkins CTY Lancaster '87 session 1)

karl@haddock.ISC.COM (Karl Heuer) (04/01/88)

[ The previous article was directed to comp.sys.m6809, but this is a language
issue.  I'm redirecting back to comp.lang.c.  --kwzh ]

In article <2108@svax.cs.cornell.edu> belmonte@sleepy.cs.cornell.edu (Matthew Belmonte) writes:
>So *why* do we never see semantics of standard functions included in
>compilers?  Because, in my opinion, it's not worth it.  It makes the compiler
>dependent on the standard libraries.  If my compiler's rules assume a
>particular implementation of a standard function, then if I change the
>implementation I'm liable to have either to change the compiler or to live
>with inefficient code.

I don't see that such a compiler would have to depend on the implementation;
just on the functional specification (which has now been standardized).  Thus,
it's quite safe for a compiler to convert, say, "memcpy" into a block-copy
instruction.  (But a safer approach is to recognize "__builtin_memcpy"
instead, and place "#define memcpy(x,y,z) __builtin_memcpy(x,y,z)" into the
appropriate header file.)

Btw, "never" is too strong.  Some C compilers already do this inlining.  With
the upcoming standard, it will probably become more popular.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

atbowler@watmath.waterloo.edu (Alan T. Bowler [SDG]) (04/04/88)

In article <517@picuxa.UUCP> gp@picuxa.UUCP (Greg Pasquariello X1190) writes:
>	These are library calls, and although the compiler will generate
>approximately the same function calling sequence, the linker will link in 
>a much larger function in printf().
>

Actually this may or may not be true.  If the library implementor
has carefully built his PRINTF code so that it is can be used
reentrantly (i.e no statics) then it is quite likely that code in
the guts of the library already references PRINTF in order to
give good error messages.  I.e. it may be near impossible to
build a C program that does not include PRINTF.  As always, there
may be good reasons for not using PRINTF in a particular situtation,
but blanket generalizations like "the linker will link in a much
larger function in printf()" just are not true across all implementations.
    Make it correct first, optimize second.