[comp.lang.c] New 'n' Improved comp.lang.c FAQ List

emily@etiquette.uu.net (Emily Postnews) (04/01/91)

                Emily Postnews Answers Your C Questions


The previous editor of this feature was an old curmudgeon with no sense
of humor and a number of decidedly conservative, old-fashioned notions
about C programming.  Therefore, the management has hired me, Emily
Postnews, noted Usenetiquette authority, to give you the answers you
want to hear.

In preparation, I have spent the last two months learning C on a PC-XT
with the highly-recommended Rotifer-C compiler.  I can see why you are
all so enamored of C; it's quite a language!  Let's begin.

                                 ------

Q: Why is the null pointer zero?

A: This is a common misconception.  In fact, the null pointer is
really 1.  This convention arose because of the PDP-11's efficient
predecrement addressing mode (which also explains why the stack grows
down).  When you pass a 1 as a null pointer, the correct internal value
(0) results after the autodecrement.

                                 ------

Q: Why doesn't this function work:

        itoa(int i)
        {
        char retbuf[5];         /* biggest int: 32769 */
        sprintf("%d", retbuf, i);
        return retbuf;
        }

A: Heavens, you left out the parentheses in the return statement.
No wonder it didn't work.

                                 ------

Q: My compiler complains when I try to add a pointer-to-int and a
pointer-to-double.

A: If ip is the pointer-to-int and dp is the pointer-to-double, you can
add them with the expression

        (double *)(int *)((int)*(char *)ip * sizeof(int) +
                                (int)*(char *)dp * sizeof(double))

You may have to reverse the leading (int *) and (double *) casts,
depending on what you want to do with the result.

You have to do the pointer scaling (multiply by sizeof int and double)
yourself, because compilers are generally too inadequate to figure out
how to do it themselves.  Sometimes we have to put up with these
annoying little inconsistencies in the language.

                                 ------

Q: I just typed in a sample program from Ed Bourbon's new book, Boffo C
Primer Triple Plus.  When I run the program, I get an annoying extra
blank line before the first prompt.  The prompts are printed with
something like

        printf("\nenter your shoe size: ");

What's going on?

A: That blank line must be coming from the previous program you ran.
The operating system, MS-DOS, automatically prints a blank line after
every program runs.  Therefore, programs should not print the last
newline themselves.  If one erroneously does, the extra newline stays in
the output buffer and ends up at the beginning of the next program.

You can fix this by clearing the buffer, when your program starts, with
the line

        fflush(stdout);

If you are using an ANSI Standard C compiler, use

        fflush(__STDOUT__);

instead, for compatibility.

                                 ------

Q: The other FAQ list recommended avoiding alloca.  What's wrong
with it?

A: That "other FAQ list" contained numerous examples of unnecessarily
pessimistic advice.  alloca neatly solves several problems which have no
other solution, and it is trivial to implement: it need only adjust the
stack pointer.  It was utter spinelessness on X3J11's part that alloca
was not adopted in the C Standard.  Go ahead and use it; any responsible
vendor will provide it as an extension.

                                 ------

Q: What's the best indentation and brace placement style?

A: Don't bother indenting; the compiler ignores whitespace anyway.
Braces epitomize the cryptic terseness for which C is notorious.  Rather
than trying to place them in such a way as to make grouping more
obvious, it is better to set up some macro #definitions:

        #define begin {
        #define end   }

Then you can use the keywords "begin" and "end" to delineate compound
statements, which will make things much clearer.

Using the preprocessor to provide "syntactic syrup" in this way can
powerfully affect the readability of a program.  I'm sure that many
readers have come up with other syntax-liberating macros (SLM's) like
these.  Why doesn't everybody post their favorite ones, and we'll
compile a complete list?

                                 ------

Q: What does "undefined order of evaluation" mean?  Why is it to be
avoided?

A: Warnings about depending upon machine-dependent evaluation order
apply only to naive, uneducated users who are not as intimately familiar
with your machine as you are.  Since you know what order your compiler
evaluates things in, you should go ahead and make use of it.  Doing so
will probably make your programs more efficient, too.

                                 ------

Q: Which is more efficient, i = i + 1 or i = 1 + i ?

A: Neither; both will generate a two- or three-operand add instruction,
with a wasteful in-line immediate constant operand, while most machines
have a much more efficient single-operand increment instruction.  My
compiler lets me use the built-in intrinsic function __inc(i) so that
the inc instruction is emitted in-line, without even using a function
call!  If your compiler doesn't have __inc(), you might have to use an
asm directive.

                                 ------

Q: How can I call interpreted BASIC from C?

A: Just shove the function call onto the input stream using the TIOCSTI
ioctl, then jump to the interpreter with system() or exec().

                                 ------

Q: How can I find out the time of day when I'm writing a C program?

A: Look at your watch, silly.

                                 ------

Q: The microprocessor in the electronic toaster I'm writing the firmware
for has a quirk: if you read a register within 3.14 microseconds of
writing it, it is cleared.  The hardware designers figured there was no
reason to operate the toaster for 0 seconds, so they arranged that a
value of 0 in the timer register turns the heating element on
indefinitely.

Last week I hand-optimized the user interface code, which sped things up
enough that some of the register accesses are coming too close on the
heels of the previous store.  The prototype toaster at my bench keeps
bursting into flames, and my co-workers are starting to complain about
the smoke.  Is there a C keyword, sort of like volatile, which will keep
the compiler from emitting code to read a value within 3.14 microseconds
of writing it?

A: Why are you posting this to comp.lang.c?  The ANSI C Standard
contains language specifically discussing embedded applications, and
distinguishes between "toasted" and "non-toasted" implementations.  Post
your question to comp.std.c, instead.

grover@big-joe.cs.unlv.edu (Kevin Grover) (04/02/91)

> [misc deleted. . .]

> Q: Why doesn't this function work:
>
>         itoa(int i)
>         {
>         char retbuf[5];         /* biggest int: 32769 */
>         sprintf("%d", retbuf, i);
>         return retbuf;
>         }
>
> A: Heavens, you left out the parentheses in the return statement.
> No wonder it didn't work.

WRONG:  The return does NOT need parans.  Also, this function should be
        declared to return char *, rather then the default int.  The
        retbuf space is temporary: you can NOT depend on it being there
	after the call.  It should be declared static.  Furthermore, the
	sprintf call is wrong:  the retbuf should preceed the format statement.

	A correct version of this program is:

        char *itoa(int i)
          {
            static char retbuf[5];         /* biggest int: 32769 */
            sprintf(retbuf, "%d", i);
            return retbuf;
          }


	Was this program even checked before being submitted?  I find the
	idea of a FAQ quite nice and feel that it can help people learning
	C very much, but blantantly incorrect answers such as this one could
	cause someone not familiar with C many problems.  (If it was a joke, 
	it should have been made clear somewhere.)

	Another note:  since that one buffer space is used to hold the results
	of all calls to this function, a call like:

		printf ("%s %s\n", itoa(x), itoa(y) );

	might, or might not work (most likely not), becuase the C code will
	convert x to ascii (in retbuf), and return the pointer, then the
	second call will convert y to ascii (in retbuf) and return the same
	pointer.  Thus, the output will be:

	y y

	rahter than:

	x y

	Again, this MIGHT work on some machines (esp. PCs) but, you should NOT
	depend on it working anywhere.  (I do know that I will NOT work on
	a SPARCstation 1 running gcc.  I tried it.)

> [misc deleted . . .]
>
> Q: Which is more efficient, i = i + 1 or i = 1 + i ?
>
> A: Neither; both will generate a two- or three-operand add instruction,
> with a wasteful in-line immediate constant operand, while most machines
> have a much more efficient single-operand increment instruction.  My
> compiler lets me use the built-in intrinsic function __inc(i) so that
> the inc instruction is emitted in-line, without even using a function
> call!  If your compiler doesn't have __inc(), you might have to use an
> asm directive.


	Why not just use the ++ operator??? (as in i++, or ++i)   Any decent
	compiler should use the ML increment function if your machine has one.


> [misc deleted . . .]
>
> Q: What's the best indentation and brace placement style?
>
> A: Don't bother indenting; the compiler ignores whitespace anyway.
> Braces epitomize the cryptic terseness for which C is notorious.  Rather
> than trying to place them in such a way as to make grouping more
> obvious, it is better to set up some macro #definitions:
> 
>         #define begin {
>         #define end   }
> 
> Then you can use the keywords "begin" and "end" to delineate compound
> statements, which will make things much clearer.
> 
> Using the preprocessor to provide "syntactic syrup" in this way can
> powerfully affect the readability of a program.  I'm sure that many
> readers have come up with other syntax-liberating macros (SLM's) like
> these.  Why doesn't everybody post their favorite ones, and we'll
> compile a complete list?


	What do you mean, DON'T BOTHER INDENTING????   Is this a joke?  Was
	this whole post a joke?  Proper indentation makes a program MUCH more
	readable (just as improper indentation makes a program virtually
	unreadable).  As to what is proper, that is a matter of opinion,
	although that are several defacto standards (such as K&R) which might
	not be the best (again opinion), but are certainly better then not
	indentation standard (my opinion.)

	While we're at it, why not forget about comments as well?  After all,
	the compiler just ignores them anyway :-) ???

-- 
  +-------------------------------------------------+----------------------+
  | Kevin Grover             UNLV Computer Science  |     Home of the      |
  | grover@cs.unlv.edu       Las Vegas, Nevada      |    Running REBELS    |
  +-------------------------------------------------+----------------------+

jinx@milton.u.washington.edu (Everyone Knows JINX) (04/02/91)

grover@big-joe.cs.unlv.edu (Kevin Grover) writes:

>> [misc deleted. . .]

>WRONG:  The return does NOT need parans.  Also, this function should be
>        declared to return char *, rather then the default int.  The
> 		...
(suffice it to say that Kevin blows a blood vessel)

April Fool's, Mr. Grover.

Jinx

bls@u02.svl.cdc.com (Brian Scearce) (04/02/91)

grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
> Apparently non-obvious April Fool's Day bogus account posts:
>> Q: Why doesn't this function work:
>>
>>         itoa(int i)
>>         {
>>         char retbuf[5];         /* biggest int: 32769 */
>>         sprintf("%d", retbuf, i);
>>         return retbuf;
>>         }
>>

>	A correct version of this program is:
>        char *itoa(int i)
>          {
>            static char retbuf[5];         /* biggest int: 32769 */
>            sprintf(retbuf, "%d", i);
>            return retbuf;
>          }

Almost, but not quite, Mr. Grover.  The *really* correct version of this:

        char *itoa(int i)
          {
            static char retbuf[5];         /* biggest int: 32768 */
            sprintf(retbuf, "%d", i);
            return retbuf;
          }

If you are going to put in comments, you should make sure they're
correct.  Actually, I delete all my comments from production code,
for efficiency.  Although the next release of my compiler is
suppossed to emit no-ops for comments, I can't afford to upgrade
right now.

>> Q: Which is more efficient, i = i + 1 or i = 1 + i ?
>> A: [ intrinsic __inc is suggested ]

>	Why not just use the ++ operator??? (as in i++, or ++i)   Any decent
>	compiler should use the ML increment function if your machine has one.

He probably just forgot.  Programmers aren't perfect, and having
so many operators in C just makes the situation worse.  A meaningful
name like __inc() is better.  If the programmer is one of the ones
smart enough to remember the C build-in operator, then he can write
a define like:

#define __inc(x) ++(x)

So nothing is lost.  Personally, I avoid ++: it makes me think of
George Orwell.

 ++good; /* Assign 0x7c0 to good */

>> Q: What's the best indentation and brace placement style?
>> A: Don't bother indenting [...]

>	What do you mean, DON'T BOTHER INDENTING????

Like comments, whitespace should be removed for efficiency.  If
you are one of the lucky few that has a compiler that can handle
whitespace efficiently, count your blessings, but don't ask the
rest of us to mutate our code to fit your compiler.

>	Is this a joke?  Was this whole post a joke?

That would be irresponsible.

Except on April 1.

To the original author: you should have posted from a real account.
I wanted to thank you without wasting bandwidth.  The N&I FAQ is
going up on my office door.

--
     Brian Scearce (bls@robin.svl.cdc.com  -or-  robin!bls@shamash.cdc.com)
    "Don't be surprised when a crack in the ice appears under your feet..."
 Any opinions expressed herein do not necessarily reflect CDC corporate policy.

fguille@issy (Francois Guillemot - Sun France Software Support) (04/02/91)

bls@u02.svl.cdc.com (Brian Scearce) writes:

    Almost, but not quite, Mr. Grover.  The *really* correct version of this:
    
            char *itoa(int i)
              {
                static char retbuf[5];         /* biggest int: 32768 */
                sprintf(retbuf, "%d", i);
                return retbuf;
              }
    
Should'nt the *really really correct* version allocate an extra character
in the retbuf array for the end of string delimiter \0 ???

I will just say that a *just a little bit more correct* version should
read:

       static char retbuf[6];         /* biggest int: 32768 */

-- 
	Francois GUILLEMOT
	SUN France
	fguille@France.Sun.COM

jar@ifi.uio.no (Jo Are Rosland) (04/02/91)

In article <31946@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes:

   grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
   > Apparently non-obvious April Fool's Day bogus account posts:

   Almost, but not quite, Mr. Grover.  The *really* correct version of this:

	   char *itoa(int i)
	     {
	       static char retbuf[5];         /* biggest int: 32768 */
	       sprintf(retbuf, "%d", i);
	       return retbuf;
	     }

Not to be picky, but

	char *itoa(int i)
	{
	    static char retbuf[7];	/* biggest int: 32767 */
	    sprintf(retbuf, "%d", i);
	    return retbuf;
	}

is really, *really* correct, provided int is stored two's-complement
in 16 bits.  FLAME SHIELD: This of course is not a portable
assumption, and the whole function is redundant, and it's interface
stinks, and the original function at least had some value as comic
relief whereas this one has none.

But all of this is probably getting rather silly, and not at all as
entertaining as the original posting, sorry ;-(
--
Jo Are Rosland
jar@ifi.uio.no

glex@wf.msc.umn.edu (Jeffrey Gleixner) (04/02/91)

In article <1991Apr1.203024.19679@unlv.edu>, grover@big-joe.cs.unlv.edu
(Kevin Grover) writes:
> 	What do you mean, DON'T BOTHER INDENTING????   Is this a joke?  Was
> 	this whole post a joke?  Proper indentation makes a program MUCH more
Some people don't get out much.  Actually the rebuttal was funnier than the
original post... I wonder if it was a joke??  ;-)
--
glex@msc.umn.edu  ===  " I don't go out with girls that say bitch'n " ===

dave@cs.arizona.edu (Dave Schaumann) (04/02/91)

In article <1991Apr1.203024.19679@unlv.edu> grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
>[much ranting deleted]
>What do you mean, DON'T BOTHER INDENTING????   Is this a joke?

Yes.

>Was this whole post a joke?

Yes.


Believe it or not, there are a few unscrupulous souls out there who don't
post consistantly dead-on serious messages.  For some reason, they feel
that satire can be a better way to get a message across than a simple
statement of the point.  Go figure.
-- 
Dave Schaumann | dave@cs.arizona.edu | Short .sig's rule!

al@unhd.unh.edu (Anthony Lapadula) (04/03/91)

In article <3739@jethro.Corp.Sun.COM> fguille@France.Sun.COM writes:
>
>    Almost, but not quite, Mr. Grover.  The *really* correct version of this:
>    
>            char *itoa(int i)
>              {
>                static char retbuf[5];         /* biggest int: 32768 */
>                sprintf(retbuf, "%d", i);
>                return retbuf;
>              }
>[....]
>
>       static char retbuf[6];         /* biggest int: 32768 */

I wanted to stay out of this discussion.  I really did....

I know this thread grew out of an April Fool's joke, but I just can't
let this pass.

Even if you know that your system has 16-bit int's (which is a poor
assumption -- we should know by now that all the world's a VAX :-),
itoa could still be requested to print out, say, "-20000", which
requires a buffer of size *7*.

-- Anthony (uunet!unhd!al, al@cs.unh.edu) Lapadula

"I would agree with you if you were right."  --  Dr Sayer, "Awakenings"

volpe@camelback.crd.ge.com (Christopher R Volpe) (04/03/91)

How could anyone have read that entire article without knowing it
was a joke? My sides are still sore.

==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

grover@big-joe.cs.unlv.edu (Kevin Grover) (04/03/91)

Okay, Okay . . . Well someone had to fall for it right?  So PLEASE, no more
mail responses, the first 30 or so clearly indicated my ignorance.   If only
we could get this kind of response to questions :-)

-- 
  +-------------------------------------------------+----------------------+
  | Kevin Grover             UNLV Computer Science  |     Home of the      |
  | grover@cs.unlv.edu       Las Vegas, Nevada      |    Running REBELS    |
  +-------------------------------------------------+----------------------+

debra@wsinis03.info.win.tue.nl (Paul De Bra) (04/03/91)

In article <3739@jethro.Corp.Sun.COM> fguille@France.Sun.COM writes:
>bls@u02.svl.cdc.com (Brian Scearce) writes:
>            char *itoa(int i)
>              {
>                static char retbuf[5];         /* biggest int: 32768 */
>                sprintf(retbuf, "%d", i);
>                return retbuf;
>              }
>Should'nt the *really really correct* version allocate an extra character
>in the retbuf array for the end of string delimiter \0 ???

Actually, this version of itoa is wrong for 2 reasons:
- retbuf should have size 7, to account for negative ints as well as the
  terminating null character.
- this version of itoa will not work as expected in a call like:
  printf("%s %s\n",itoa(2),itoa(3));
  the only way to do it right is to allocate memory for the buffer on each
  call. but then, freeing that memory becomes a problem as it cannot be done
  inside itoa...

Paul.
(debra@win.tue.nl)

timr@gssc.UUCP (Tim Roberts) (04/04/91)

In article <3739@jethro.Corp.Sun.COM> fguille@France.Sun.COM writes:
:>bls@u02.svl.cdc.com (Brian Scearce) writes:
:>    Almost, but not quite, Mr. Grover.  The *really* correct version of this:
:>            char *itoa(int i) {
:>                static char retbuf[5];         /* biggest int: 32768 */
:>                sprintf(retbuf, "%d", i);
:>                return retbuf;
:>              }
:>Should'nt the *really really correct* version allocate an extra character
:>in the retbuf array for the end of string delimiter \0 ???
:>
:>I will just say that a *just a little bit more correct* version should read:
:>
:>       static char retbuf[6];         /* biggest int: 32768 */

Shouldn't the *really truly one-true-God correct* version of this read:

        static char retbuf[6];         /* biggest int: 32767 */
    
And isn't this really really just a little bit more silly than we all need?



-- 
timr@gssc.gss.com	Tim N Roberts, CCP	Graphic Software Systems
						Beaverton, OR

This is a very long palindrome. .emordnilap gnol yrev a si sihT

adrian@mti.mti.com (Adrian McCarthy) (04/04/91)

In article <31946@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes:
>grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
>> Apparently non-obvious April Fool's Day bogus account posts:
>>...
>Almost, but not quite, Mr. Grover.  The *really* correct version of this:
>
>        char *itoa(int i)
>          {
>            static char retbuf[5];         /* biggest int: 32768 */
>            sprintf(retbuf, "%d", i);
>            return retbuf;
>          }

I'm not sure if people are really trying to clear this up, or if they're
just trying to propagate the joke.  At the risk of being a fool...

We still haven't got it.  Since the biggest int may be five (5) characters,
retbuf should be at least size (6) characters long to hold the '\0'
character at the end.  Then again, since this int isn't unsigned, you
really need another character to make sure you can hold the minus sign.
This is a common mistake.

If you want to make the code disgustingly portable (and assume an ANSI
compiler), you can drop the assumption about the size of the largest int
by using limits.h, sizeof, and a preprocessor trick (see below).

To keep lint quiet, you might want to explicity ignore the return value
of sprintf by placing "(void)" before it.  If you are suspicious of your
C run-time library, check the return for reasonable ranges:

	(r > 0) && (r < sizeof(retbuf))

(Remember that sprintf doesn't include the '\0' terminator in its return
value.)

	#include <limits.h>
	#define QUOTE(a)	#a
	char *itoa(int i)
	{
		static char	retbuf[sizeof(QUOTE(INT_MIN))];
		/*
		 * I *think* the above is a legitimate use of sizeof.  Can
		 * any standard gurus confirm or deny this?
		 */

		(void) sprintf(retbuf, "%d", i);
		return retbuf;
	}

Aid.  (adrian@gonzo.mti.com)

dgil@pa.reuter.COM (Dave Gillett) (04/04/91)

In <1991Apr1.203024.19679@unlv.edu> grover@big-joe.cs.unlv.edu (Kevin Grover) writes:

>	A correct version of this program is:

>        char *itoa(int i)
>          {
>            static char retbuf[5];         /* biggest int: 32769 */
>            sprintf(retbuf, "%d", i);
>            return retbuf;
>          }


     Bzzzt!

     For this purpose, the "biggest" integer (assuming 16-bit ints, as Kevin
has...) is

               -32768

     That's *6* characters long.

                                                   Dave

torek@elf.ee.lbl.gov (Chris Torek) (04/04/91)

In article <1780@mti.mti.com> adrian@mti.UUCP (Adrian McCarthy) writes:
>I'm not sure if people are really trying to clear this up, or if they're
>just trying to propagate the joke.  At the risk of being a fool...

(I think people are getting it wrong, rather than perpetuating the
Emily Postnews bit.  Anyway, this sort of joke works the way Manny
described to Mike: `Use it once, you're a wit.  Use it twice, you're
a half-wit.'  `Geometric progression?'  `Or worse.')

>	#include <limits.h>
>	#define QUOTE(a)	#a
>		static char	retbuf[sizeof(QUOTE(INT_MIN))];

This almost works: it expands to

		static char	retbuf[sizeof("INT_MIN")];

You must use two levels of macro evaluation:

	#define XQUOTE(a)	QUOTE(a)	/* expanded quote */
		static char retbuf[sizeof(XQUOTE(INT_MIN))];
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

karl@ima.isc.com (Karl Heuer) (04/04/91)

In article <11742@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
>You must use two levels of macro evaluation:
>	#define XQUOTE(a)	QUOTE(a)	/* expanded quote */
>		static char retbuf[sizeof(XQUOTE(INT_MIN))];

But you still don't necessarily get the right answer, since INT_MIN might not
be implemented as a simple digit-string.  If <limits.h> defines INT_MIN as
(1<<31), the sizeof() will only return 8.

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

matthew1@garfield.cs.mun.ca (Matthew J. Newhook) (04/04/91)

bls@u02.svl.cdc.com (Brian Scearce) writes:

>grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
>> Apparently non-obvious April Fool's Day bogus account posts:
>>> Q: Why doesn't this function work:
>>>
>>>         itoa(int i)
>>>         {
>>>         char retbuf[5];         /* biggest int: 32769 */
>>>         sprintf("%d", retbuf, i);
>>>         return retbuf;
>>>         }
>>>

>>    A correct version of this program is:
>>        char *itoa(int i)
>>          {
>>            static char retbuf[5];         /* biggest int: 32769 */
>>            sprintf(retbuf, "%d", i);
>>            return retbuf;
>>          }

>Almost, but not quite, Mr. Grover.  The *really* correct version of this:

>        char *itoa(int i)
>          {
>            static char retbuf[5];         /* biggest int: 32768 */
>            sprintf(retbuf, "%d", i);
>            return retbuf;
>          }

Actually here is a correct (portable) version (assuming that you want to 
keep a static character buffer, and not use a newly malloc'd one each time).

#include <math.h>

char *itoa(int i)
{
    static int first = 1;
    static char *s;

    if (first) { /* IF FIRST TIME ALLOCATE MEMORY FOR STRING */
        first = 0;
        s = (char *) 
        malloc((long) ceil(log10(pow(2, (double) sizeof(int) * 8))) +1);
        if (!s) {
            fprintf(stderr,"malloc failed\n");
            exit(1);
        }
    }

    sprintf(s, "%d", i);
    return s;
}

This is portable, 'cause it always assigns the correct value to the size of
the array, without depending on the sizeof(int) == 2.

Matthew Newhook
        

-- 
----------------matthew1@garfield.cs.mun.ca 
"Living in the limelight; the universal dream for those who wish to 
seem. Those who wish to be must put aside the alienation, get on with 
the facination, the real relation, the underlying theme" - Rush

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (04/04/91)

In article <11742@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
> 		static char retbuf[sizeof(XQUOTE(INT_MIN))];

Or, for those of us who can't remember how sizeof works:

  static char retbuf[] = XQUOTE(INT_MIN);

---Dan

krey@i30fs1.NoSubdomain.NoDomain (Andreas Krey) (04/04/91)

In article <1991Apr4.024300.19969@garfield.cs.mun.ca>, matthew1@garfield.cs.mun.ca (Matthew J. Newhook) writes:
|> bls@u02.svl.cdc.com (Brian Scearce) writes:
|> 
|> >grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
|> >> Apparently non-obvious April Fool's Day bogus account posts:
|> >>> Q: Why doesn't this function work:
|> >>>
|> >>>         itoa(int i)
|> >>>         {
|> >>>         char retbuf[5];         /* biggest int: 32769 */
|> >>>         sprintf("%d", retbuf, i);
|> >>>         return retbuf;
|> >>>         }
|> >>>
|> 
|> >>    A correct version of this program is:
|> >>        char *itoa(int i)
|> >>          {
|> >>            static char retbuf[5];         /* biggest int: 32769 */
|> >>            sprintf(retbuf, "%d", i);
|> >>            return retbuf;
|> >>          }
|> 
|> >Almost, but not quite, Mr. Grover.  The *really* correct version of this:
|> 
|> >        char *itoa(int i)
|> >          {
|> >            static char retbuf[5];         /* biggest int: 32768 */
|> >            sprintf(retbuf, "%d", i);
|> >            return retbuf;
|> >          }
|> 
|> Actually here is a correct (portable) version (assuming that you want to 
|> keep a static character buffer, and not use a newly malloc'd one each time).
|> 
|> #include <math.h>
|> 
|> char *itoa(int i)
|> {
|>     static int first = 1;
|>     static char *s;
|> 
|>     if (first) { /* IF FIRST TIME ALLOCATE MEMORY FOR STRING */
|>         first = 0;
|>         s = (char *) 
|>         malloc((long) ceil(log10(pow(2, (double) sizeof(int) * 8))) +1);
|>         if (!s) {
|>             fprintf(stderr,"malloc failed\n");
|>             exit(1);
|>         }
|>     }
|> 
|>     sprintf(s, "%d", i);
|>     return s;
|> }
|> 
|> This is portable, 'cause it always assigns the correct value to the size of
|> the array, without depending on the sizeof(int) == 2.
|> 
|> Matthew Newhook
|>         
|> 
|> -- 
|> ----------------matthew1@garfield.cs.mun.ca 
|> "Living in the limelight; the universal dream for those who wish to 
|> seem. Those who wish to be must put aside the alienation, get on with 
|> the facination, the real relation, the underlying theme" - Rush

Actually the correct simple solution is:
        char *itoa(int i)
          {
            static char retbuf[6];         /* biggest int: 32768 */
            sprintf(retbuf, "%d", i);
            return retbuf;
          }

since the resulting string contains five digits and a trailing zero.
(note the [6]). If you do not rely on sizeof(int)==2, I usually set
the array size to a sufficiently big value. 30 will probably be enough
for the next few computer generations, and will then generate really nice
(hard to find) bugs...

(I didn't bother to check whether the complicated expression takes the
trailing '\0' into account. Also I only read this group if there are
fewer than <limit> articles, so my point may have been pointed out.)
-- 
Andy

-------------------------------------------
Zeit ist Geld. Aber Geld ist keine Zeit.
[Intl: Time is money. But money isn't time.]

paul@sequoia.cray.com (Paul Dow (CRI-UK)) (04/04/91)

Will this never end.....   Here's my three ha'pence....

In article <1991Apr4.024300.19969@garfield.cs.mun.ca>, matthew1@garfield.cs.mun.ca (Matthew J. Newhook) writes:
|> bls@u02.svl.cdc.com (Brian Scearce) writes:
|> 
|> >grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
|> >> Apparently non-obvious April Fool's Day bogus account posts:
|> >>> Q: Why doesn't this function work:
|> >>>
|> >>>         itoa(int i)
|> >>>         {
|> >>>         char retbuf[5];         /* biggest int: 32769 */
|> >>>         sprintf("%d", retbuf, i);
|> >>>         return retbuf;
|> >>>         }
|> >>>
|> 
|> >>    A correct version of this program is:
|> >>        char *itoa(int i)
|> >>          {
|> >>            static char retbuf[5];         /* biggest int: 32769 */
|> >>            sprintf(retbuf, "%d", i);
|> >>            return retbuf;
|> >>          }
|> 
|> >Almost, but not quite, Mr. Grover.  The *really* correct version of this:
|> 
|> >        char *itoa(int i)
|> >          {
|> >            static char retbuf[5];         /* biggest int: 32768 */
|> >            sprintf(retbuf, "%d", i);
|> >            return retbuf;
|> >          }
|> 
|> Actually here is a correct (portable) version (assuming that you want to 
|> keep a static character buffer, and not use a newly malloc'd one each time).
|> 
|> #include <math.h>
|> 
|> char *itoa(int i)
|> {
|>     static int first = 1;
|>     static char *s;
|> 
|>     if (first) { /* IF FIRST TIME ALLOCATE MEMORY FOR STRING */
|>         first = 0;
|>         s = (char *) 
|>         malloc((long) ceil(log10(pow(2, (double) sizeof(int) * 8))) +1);
|>         if (!s) {
|>             fprintf(stderr,"malloc failed\n");
|>             exit(1);
|>         }
|>     }
|> 
|>     sprintf(s, "%d", i);
|>     return s;
|> }
|> 
|> This is portable, 'cause it always assigns the correct value to the size of
|> the array, without depending on the sizeof(int) == 2.
|> 
|> Matthew Newhook
|>         


It is easy to say that things are "correct" & "portable".  How often have
people been flamed in this newsgroup (and others) for that.  A lot of people
are put of replying to questions for fear of being flamed.  Mind you, if
the replies were framed as suggestions as opposed to "correct"/"portable" etc,
then they would not irritate the "flamer" so much.

Anyhow, enough of that sideline, let us look at the last example above and ask
a few questions ?

Q1)	The "*8" I presume is for the numbers of bits in a byte.  Are there
	problems here on a 9 bit machine?  I don't have access to any such		 		   	machines, so I cannot test this out.

Q2)	Should the first parameter to pow() be a double - the compiler may not
	support prototypes.

Q3)	The "+1" appears to be for the terminating NULL character.  Has any
	space being allowed for a leading "-" sign ?

Q4)	Malloc is being passed a "long" type for the number of bytes.  Should
	this be an unsigned (int)  [it is on my SunOS 4.1 system].

Q5)	If the malloc fails, then a string is written to stderr.  Is this
	accetable?  Is it also acceptable to exit at that point ?
        This may not be acceptable to some applications which might not support a
        stderr per se ["stderr" might exist, but is it valid to use it ?].
	I have encountered this problem with assrted C libraries on several
	systems.

	I have to admit that it is good to see return values checked.  Code that
	ignores return values is the bane of my life.

Suggestions:

Here are a few things that I would think about.  They would not change the functionality, but may be worth considering - depending on ones viewpoint.

S1)	I would tend to use a NULL/not NULL test for the pointer to determine if
	the buffer needed to be allocated.

S2)	It took a bit of thinking about to work out what the

		malloc((long) ceil(log10(pow(2, (double) sizeof(int) * 8))) +1);

	was doing.  Can this be simplified ?

S3)	It took me a second or two to work out where the result of the malloc was
	going. It would have helped me of the malloc line was indented more.


Paul.

[All disclaimers may be assumed]

kentd@FtCollins.NCR.com (Kent.Dalton) (04/04/91)

>>>>> On 2 Apr 91 11:38:36 GMT, fguille@issy (Francois Guillemot - Sun France Software Support) said:


 > Should'nt the *really really correct* version allocate an extra character
 > in the retbuf array for the end of string delimiter \0 ???

 No! No! No! that's not allowed anymore... apparently you haven't heard
that the NULL terminater has been patented?! Sheesh, where've you been!

Sorry folks, I couldn't resist.

:^) ;^) :^)   <-- amazing three frame "multimedia" smiley/wink animation
                  included free of charge. Save CPU time, use your brain
                  to process it.

--
/**************************************************************************/
/* Kent Dalton                     * EMail: Kent.Dalton@FtCollins.NCR.COM */
/* NCR Microelectronics            *   CIS: 72320,3306                    */
/* 2001 Danfield Ct. MS470A        *                                      */
/* Fort Collins, Colorado 80525    * (303) 223-5100 X-319                 */
/**************************************************************************/
Fortune:
"Kirk to Enterprise -- beam down yeoman Rand and a six-pack."

dmturne@PacBell.COM (Dave Turner) (04/05/91)

In article <849@saxony.pa.reuter.COM> dgil@pa.reuter.COM (Dave Gillett) writes:
.In <1991Apr1.203024.19679@unlv.edu> grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
.>        char *itoa(int i)
.>          {
.>            static char retbuf[5];         /* biggest int: 32769 */
.>            sprintf(retbuf, "%d", i);
.>            return retbuf;
.>          }
.     Bzzzt!
.     For this purpose, the "biggest" integer (assuming 16-bit ints, as Kevin
.has...) is
.               -32768
.     That's *6* characters long.

Bzzzt!

Counting the \0 placed at the end of the string by sprintf,
that's *7* characters long.



-- 
Dave Turner	415/823-2001	{att,bellcore,sun,ames,decwrl}!pacbell!dmturne

scs@adam.mit.edu (Steve Summit) (04/05/91)

I've been trying (well, actually, that's not *strictly* true :-) )
to stay out of this, but I'll mention a couple of things.

First of all, as should by now be obvious, if you haven't found
at least *five* reasons why

	char retbuf[5];		/* biggest int: 32769 */

is wrong, think some more, or read all the followups which have
been posted so far, and take the union.

In article <1780@mti.mti.com> adrian@mti.UUCP (Adrian McCarthy)
touches on the least-observed problem by writing:
>If you want to make the code disgustingly portable (and assume an ANSI
>compiler), you can drop the assumption about the size of the largest int
>by using limits.h, sizeof, and a preprocessor trick (see below).

I wouldn't disparage this level of portability at all.  There's
no reason to assume that ints are 16 bits.  (If you want to
assume that a type is 16 bits, you can make your intentions
clearer by declaring it as a short.)

Some increasingly outlandish "solutions" to the problem of sizing
an int-to-ascii return buffer are being offered.  The variations
on sizeof(INT_MAX) are imaginative (and new to me), but, as Karl
has noted, they can't work, and they're too convoluted, anyway.
The explicit run-time log10() calculation, while on the right
track, is unnecessarily baroque.  Much the same thing can be
accomplished quite cleanly (he says) with

	static char retbuf[sizeof(int) * CHAR_BIT / 3 + 1 + 1 + 1];
					/* +1 for /3 truncation */
					/* +1 for leading - */
					/* +1 for trailing \0 */

This gives you a buffer big enough for a base-8 conversion, which
is marginally bigger than you need for a base-10 conversion.

(Side note: when sizing buffers like this, I usually *don't* fold
all the +1 fudge factors together, preferring to leave them
explicit and separately explained, as shown.)

                                            Steve Summit
                                            scs@adam.mit.edu

matthew1@garfield.cs.mun.ca (Matthew J. Newhook) (04/05/91)

paul@sequoia.cray.com (Paul Dow (CRI-UK)) writes:


>Will this never end.....   Here's my three ha'pence....

>In article <1991Apr4.024300.19969@garfield.cs.mun.ca>, matthew1@garfield.cs.mun.ca (Matthew J. Newhook) writes:
[ stuff deleted .. ]
>|> Actually here is a correct (portable) version (assuming that you want to 
>|> keep a static character buffer, and not use a newly malloc'd one each time).
>|> 
>|> #include <math.h>
>|> 
>|> char *itoa(int i)
>|> {
>|>     static int first = 1;
>|>     static char *s;
>|> 
>|>     if (first) { /* IF FIRST TIME ALLOCATE MEMORY FOR STRING */
>|>         first = 0;
>|>         s = (char *) 
>|>         malloc((long) ceil(log10(pow(2, (double) sizeof(int) * 8))) +1);
>|>         if (!s) {
>|>             fprintf(stderr,"malloc failed\n");
>|>             exit(1);
>|>         }
>|>     }
>|> 
>|>     sprintf(s, "%d", i);
>|>     return s;
>|> }
>|> 
>|> This is portable, 'cause it always assigns the correct value to the size of
>|> the array, without depending on the sizeof(int) == 2.
>|> 
>|> Matthew Newhook
>|>         


>It is easy to say that things are "correct" & "portable".  How often have
>people been flamed in this newsgroup (and others) for that.  A lot of people
>are put of replying to questions for fear of being flamed.  Mind you, if
>the replies were framed as suggestions as opposed to "correct"/"portable" etc,
>then they would not irritate the "flamer" so much.

>Anyhow, enough of that sideline, let us look at the last example above and ask
>a few questions ?

>Q1)    The "*8" I presume is for the numbers of bits in a byte.  Are there
>    problems here on a 9 bit machine?  I don't have access to any such                        machines, so I cannot test this out.

>Q2)    Should the first parameter to pow() be a double - the compiler may not
>    support prototypes.

I'm using ANSI C, and the standard says pow takes double.

>Q3)    The "+1" appears to be for the terminating NULL character.  Has any
>    space being allowed for a leading "-" sign ?

woops...

>Q4)    Malloc is being passed a "long" type for the number of bytes.  Should
>    this be an unsigned (int)  [it is on my SunOS 4.1 system].

Should actually be size_t according to the standard.

>Q5)    If the malloc fails, then a string is written to stderr.  Is this
>    accetable?  Is it also acceptable to exit at that point ?
>        This may not be acceptable to some applications which might not support a
>        stderr per se ["stderr" might exist, but is it valid to use it ?].
>    I have encountered this problem with assrted C libraries on several
>    systems.

It was acceptable for this example...

>    I have to admit that it is good to see return values checked.  Code that
>    ignores return values is the bane of my life.

>Suggestions:

>Here are a few things that I would think about.  They would not change the functionality, but may be worth considering - depending on ones viewpoint.

>S1)    I would tend to use a NULL/not NULL test for the pointer to determine if
>    the buffer needed to be allocated.

This is a moot point, IMHO.  "if (!p)" is a common enough expression...

>S2)    It took a bit of thinking about to work out what the
>        malloc((long) ceil(log10(pow(2, (double) sizeof(int) * 8))) +1);
>    was doing.  Can this be simplified ?

I don't know can it?  Any ideas anyone? 
>S3) It took me a second or two to work out where the result of the malloc was 
>     going. It would have helped me of the malloc line was indented more.  
> Possibly, but where else was the malloc going?  
Actually, I think someone posted a better solution to mine later...  
It went like this, if your limits.h defines INT_MIN in the right manner...  
(ie. -2147483648 instead of (1 << 31) or whatever).  And, of course, you 
use ANSI C.

#include <limits.h>
#define QUOTE(a)    #a
char *itoa(int i)
{
    static char retbuf[sizeof(QUOTE(INT_MIN)];
                      ^^^^^^^^ shouldn't there be a +1 here for the null char?
    /*
     * I *think* the above is a legitimate use of sizeof.  Can
     * any standard gurus confirm or deny this?
     */

    (void) sprintf(retbuf, "%d", i);
    return retbuf;
}

Aid.  (adrian@gonzo.mti.com)
>Paul.

>[All disclaimers may be assumed]
Matthew Newhook
-- 
----------------matthew1@garfield.cs.mun.ca 
"Living in the limelight; the universal dream for those who wish to 
seem. Those who wish to be must put aside the alienation, get on with 
the facination, the real relation, the underlying theme" - Rush

msb@sq.sq.com (Mark Brader) (04/06/91)

Karl Heuer (karl@ima.isc.com) writes:
> In article <11742@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
> >You must use two levels of macro evaluation:
> >	#define XQUOTE(a)	QUOTE(a)	/* expanded quote */
> >		static char retbuf[sizeof(XQUOTE(INT_MIN))];
> 
> But you still don't necessarily get the right answer, since INT_MIN might not
> be implemented as a simple digit-string.  If <limits.h> defines INT_MIN as
> (1<<31), the sizeof() will only return 8.

Gee, this is fun!  Okay, if we're assuming ANSI C, we have CHAR_BIT
available, and this is also the conversion factor from sizeof's result
to bits.  Therefore...

	#define CHAR_BIT 8
	#define	LOG2	.30102999566398119521373889472449302676818988146211
			/* base 10 logarithm of 2 */

	static char retbuf[(int)((sizeof(int)*CHAR_BIT - 1) * LOG2) + 3];
			/* -1 corrects for the sign bit; +3 corrects for
			   a possible '-', for the trailing '\0', and for
			   the downward rounding on conversion to int. */

Simple, eh?
-- 
Mark Brader, Toronto	    "If you feel [that Doug Gwyn] has a bad attitude,
utzoo!sq!msb, msb@sq.com     then use lint (or Chris Torek...)" -- Joe English

This article is in the public domain.  *I* certainly don't want anything
further to do with it.

hendrik@zeusa.UUCP (Hendrik Vermooten) (04/06/91)

In article <1991Apr1.203024.19679@unlv.edu>, grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
> > [misc deleted. . .]
> > Q: Why doesn't this function work:
> >
> >         char *itoa(int i)
> >         {
> >         static char retbuf[5];         /* biggest int: 32769 */
> >         sprintf("%d", retbuf, i);
> >         return retbuf;
> >         }

WOW!
char retbuf[5];         /* biggest int: 32769 */

Watch it: 5 isn't enough; what about -32767 followed by a '\0': it has
to be char retbuf[7];

Maybe this is a way of teaching beginning C users how C can overwrite the
local stack frame and make a DOS machine freeze up and a UNIX box coredump :-)
-- 
--------------------------------------------------------------------------
Hendrik Vermooten, ZEUS software    TEL +27 12 64-5507, FAX +27 12 64-8382
Bang: ..!uunet!ddsw1!olsa99!zeusa!hendrik     or        hendrik@zeusa.UUCP
--------------------------------------------------------------------------

theo@rascal.UUCP (T. Kramer) (04/09/91)

In article <906@zeusa.UUCP> hendrik@zeusa.UUCP (Hendrik Vermooten) writes:
>In article <1991Apr1.203024.19679@unlv.edu>, grover@big-joe.cs.unlv.edu (Kevin Grover) writes:
>> > [misc deleted. . .]
>> > Q: Why doesn't this function work:
>> >
>> >         char *itoa(int i)
>> >         {
>> >         static char retbuf[5];         /* biggest int: 32769 */
>> >         sprintf("%d", retbuf, i);
>> >         return retbuf;
>> >         }
>
>WOW!


Another WOW on the sprintf statement which must read as follows:

    sprintf(retbuf, "%d", i);

+-----------------------------+----------------------------------------------+
| theo@rascal                 | Roll on C++                                  |
+-----------------------------+----------------------------------------------+