itoa'd you so?

Charles Curley charlescurley at charlescurley.com
Fri Sep 21 17:32:27 MDT 2007


On Fri, Sep 21, 2007 at 04:11:44PM -0600, Dave Smith wrote:
> Charles Curley wrote:
> >Ah, good. Did you finally get around to looking at the solution I
> >posted to this thread two days ago?
> >  
> 
> Yup, it's pretty nice with only a few warts. It doesn't work for zero or 
> INT_MIN.

Picky, picky.

OK, 0 is a likely value in an embedded context, so I added code for
that. I have two return statements, which would save a branch
instruction on some compilers, but maybe not on others.

I didn't handle INT_MIN because it's a boundary condition, and not a
likely value. If INT_MIN is likely, the caller should be using longs,
and hope they are larger than ints (not required by ANSI).

Also, I'm not wild about your solution because it isn't portable to
different int sizes, as you noted. A good embedded library function
should be as portable as possible, but that comes after speed and
compactness, and your string and code will take up valuable ROM space.

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

char *itoa (int value, char *buffer)
{
    int i = 0;

    /* I have no way of knowing the size of the incoming buffer, so I
     * have to build in a buffer, then copy into the given one. strcat
     * is likely more efficient and faster than strncat, and probably
     * coded in assembler. */
    char tmp[SIZE+1];

    tmp[SIZE] = 0;

    if (value) {

        /* For negative numbers, set the sign. Having done that, do
         * the conversion as a positive number. */
        if (value < 0) {
            strcat (buffer, "-");
            value = 0 - value;
        }

        while (value) {
            i++;

            /* Since we are starting at the right end of the string, we
             * fill our temporary buffer from the right. This is likely
             * another trick the examiner wanted. */
            tmp[SIZE-i] = digit (value%base);
            value = value/base;
        }
        strcat (buffer, &tmp[SIZE-i]);
        return;                 /* Unstructured! Unstructured! */
    } else {
        /* Handle the case of 0. */
        strcat (buffer, "0");
    }
}
--------------------------------------------------

> It also crashes at random points (sometimes after 6700 
> invocations, sometimes after 5001, sometimes after 8105, etc) when run 
> in a for loop.

Odd. Any thoughts on why? I haven't tried it yet. I don't see any
likely buffer overflows. Maybe padding SIZE would help??

What did you used for base? If that's large enough, then it could
cause an overflow in digit. The largest safe value for base is going
to be compiler and and processor dependent, but probably not very
useful.

> 
> My version skips the strcat() at the end of itoa() in favor of just 
> returning a char* that points at where my itoa() put the string in the 
> specified buffer. The caller can then know where to find the int. It 
> saves a bit of time, but at the slight cost of a somewhat bulky API.

Bulky and confusing. For one thing, the caller has to know how large
to make the buffer, so has to know something about the processor,
which reduces portability. Portability is not high on the list of
features for embedded code, but still there. And it is higher for
library functions.

A cleaner way to do it would be to malloc a buffer, fill and return
that. But that has two problems: the caller has then to free it, and
likely will have to strcat into a string already under construction.

I don't believe there is a good solution here.

> 
> 
> Here's my code:

It's a pretty good solution. A few nitpicks. Some of those are based
on quirks of oddball compilers and processors I've met....

> 
> #include <stdio.h>
> #include <string.h>
> #include <limits.h>
> #include <stdlib.h>
> 
> // This is a special case. Redefine it for platforms with a different 
> value of INT_MIN:
> #define INT_MIN_STRING "-2147483648"
> 
> // Writes the value in ascii into buf, and returns a pointer inside
> // buf where the ascii string begins. The string will be null
> // terminated
> char* itoa( int value, char *buf, int buflen )
> {
>    // Write the number from the end of the buffer, right-to-left:
>    int pos = buflen - 1;
> 
>    buf[pos--] = '\0';
> 
>    // Special case for zero:
>    if( value == 0 )

Some 16 bit compilers are stupid enough to compile the comparison
instruction instead of using a TST instruction for this (assuming the
processor has a TST instruction), so I did this as

if (value)


>    {
>        buf[pos--] = '0';

I'd put a return here. I know, unstructured. This is embedded code; we
bend the rules; Henry Kissinger would admire it.


>    }
>    // You can't take the absolute value of INT_MIN, because it would be 
> too long, and
>    // overflow INT_MAX, and result in INT_MIN again, so it's a special 
> case.
>    else if( value == INT_MIN )
>    {
>        strcpy( buf, INT_MIN_STRING );
>        return buf;
>    }
>    // Done with special cases. Do the generic case:
>    else
>    {
>        int i = abs( value );

I did the abs with a subtraction instruction because I don't know if
the abs function is declared inline. If it isn't, I've saved a JSR
call and return at run time.

> 
>        // Write each 10's place value, starting at the right:
>        do
>        {
>            buf[pos--] = '0' + (i % 10);
>        }
>        while( i /= 10 );
> 
>        // Prepend a negative sign for negative values:
>        if( value < 0 )
>        {
>            buf[pos--] = '-';
>        }
>    }
> 
>    // Return a pointer into the buf where we finished writing
>    // the front of the string:
>    return &(buf[pos+1]);
> }
> 
> 
> --Dave
> 
> /*
> PLUG: http://plug.org, #utah on irc.freenode.net
> Unsubscribe: http://plug.org/mailman/options/plug
> Don't fear the penguin.
> */

-- 

Charles Curley                  /"\    ASCII Ribbon Campaign
Looking for fine software       \ /    Respect for open standards
and/or writing?                  X     No HTML/RTF in email
http://www.charlescurley.com    / \    No M$ Word docs in email

Key fingerprint = CE5C 6645 A45A 64E4 94C0  809C FFF6 4C48 4ECD DFDB
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://plug.org/pipermail/plug/attachments/20070921/91519b34/attachment.bin 


More information about the PLUG mailing list