Newbie - itoa implementation

M

Michael Mair

This approach still fails on implementations where
unsigned int has only as many value bits as int
(that is, doesn't have a value bit for the sign bit
of int).

True. However, one at least avoids undefined behaviour.

The above problem basically was my motivation for exploring the /-10
approach for negative "a" mentioned elsethread.

Cheers
Michael
 
B

Barry Schwarz

Hi.

Just as a learning exercise, I've come up with an implementation of
itoa() without using something like sprintf. However, I can't figure
out how to extend it to deal with negative numbers - any help
appreciated!

<snip>

Hi - thanks for all the comments and explanations!

I now have this as my itoa function ...

char * itoa(int a)
{
static char str[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];

int i = sizeof(str) - 1;

if(a < 0)
{
printf("-");

Your function does not print the value. It creates a string. Why do
you print the minus sign when you have no idea how the calling
function will use the string you return? If the only valid use of the
string you return will be to print it, then it is not an "itoa"
function.
a = -a;
}

do
{
str[--i] = '0' + a % 10;
}
while ((a = a / 10) && i >= 0);

return &str;
}

I also have a version with ...

if(a < 0)
{
printf("-");

a = (1U - (1U + a));
}

Following Michael Mair's suggestion for a modification.
This may result in a signed overflow for INT_MIN on 2's complement machines which in
turn yields wrong values.

However - I don't understand the comment - can anyone explain this
please?

MQ wrote
You can't pass a pointer to a static char array. It will not work how
you expect it to work. If you make three calls to the function

Eg.
char * a = itoa(6);
char * b = itoa(7);
char * c = itoa(8);

<snip>

Yes, I agree that this is not so 'normal', but I decided to go this way
having pretty much come up with the same arguments/comments as Snis
Pilbor did.

Interestingly (I think), I had a look on Krugle (www.krugle.com) for
other itoa implementations, and there seem to be a lot that rely on the
caller freeing a buffer that's been malloc'ed. A further refined
search (itoa.c malloc) shows this is pretty popular and I was wondering
whether this approach (using malloc) was thought of as 'more risky'
than using a static internal buffer?

Also, I haven't yet found a Krugle example that uses Michael Mairs'
suggestion, i.e., most use the if(a < 0) a = -a; manipulation - so, I
was wondering about their robustness (the source found via Krugle)?

Cheers,

gareth



Remove del for email
 
D

Dave Thompson

pete wrote:
int main(void)
{
char a[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char b[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char c[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
(to allocate enough space for a conversion to decimal)
A question: is that valid C89, too? gcc accepts it
with -std=c89 -pedantic-errors, but I was under the impression that integer
constant expressions could not contain floating point arithmetic.
I think you're right and it's not allowed/guaranteed by the Standard.
But there is also an 'escape clause' that 'An implementation may
accept other forms of constant expressions.' It doesn't specifically
apply this to i.c.e.s but it doesn't exclude it either.

Maybe gcc already folded the constant down to (size_t)9.4 + 3,
which does satisfy the Standard's description, before checking.

OTOH, I see no great need to compute this so exactly. I usually just
use nbits / 3 + slop, which is IMJ easier to write and to read: I
think it as 'space for octal, which is also plenty for decimal'.

- David.Thompson1 at worldnet.att.net
 
P

pete

Dave said:
pete wrote:
int main(void)
{
char a[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char b[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char c[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
(to allocate enough space for a conversion to decimal)
A question: is that valid C89, too? gcc accepts it
with -std=c89 -pedantic-errors,
but I was under the impression that integer
constant expressions could not contain floating point arithmetic.
I think you're right and it's not allowed/guaranteed by the Standard.

I disagree.
The "floating constant" part of the above expression,
is the immediate operand of cast.

N869
6.6 Constant expressions

[#6] An integer constant expression shall have integer
type and shall only have operands that are integer
constants, enumeration constants, character constants,
sizeof expressions whose results are integer constants, and
floating constants that are the immediate operands of casts.
 
J

Jordan Abel

2006-08-21 said:
Dave said:
pete wrote:
int main(void)
{
char a[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char b[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char c[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
(to allocate enough space for a conversion to decimal)
A question: is that valid C89, too? gcc accepts it
with -std=c89 -pedantic-errors,
but I was under the impression that integer
constant expressions could not contain floating point arithmetic.
I think you're right and it's not allowed/guaranteed by the Standard.

I disagree.
The "floating constant" part of the above expression,
is the immediate operand of cast.

An expression involving a floating-point arithmetic operator (especially
one involving the division operator) is _not_ a "constant".
 
P

pete

Jordan said:
2006-08-21 said:
Dave said:
pete wrote:

int main(void)
{
char a[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char b[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char c[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];

(to allocate enough space for a conversion to decimal)

A question: is that valid C89, too? gcc accepts it
with -std=c89 -pedantic-errors,
but I was under the impression that integer
constant expressions could not contain floating point arithmetic.

I think you're right
and it's not allowed/guaranteed by the Standard.

I disagree.
The "floating constant" part of the above expression,
is the immediate operand of cast.

An expression involving a floating-point
arithmetic operator (especially
one involving the division operator) is _not_ a "constant".

Then I guess I'll just have to change it to division by 3 instead.
 
E

ena8t8si

Jordan said:
2006-08-21 said:
Dave said:
pete wrote:

int main(void)
{
char a[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char b[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char c[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];

(to allocate enough space for a conversion to decimal)

A question: is that valid C89, too? gcc accepts it
with -std=c89 -pedantic-errors,
but I was under the impression that integer
constant expressions could not contain floating point arithmetic.

I think you're right and it's not allowed/guaranteed by the Standard.

I disagree.
The "floating constant" part of the above expression,
is the immediate operand of cast.

An expression involving a floating-point arithmetic operator (especially
one involving the division operator) is _not_ a "constant".

Kind of. First what you mean is that it isn't an integer
constant expression. Second the Standard doesn't say that
floating point operations are forbidden, only that floating
point constants must be immediately casted to an integer
type. The expression above is illegal because 3.3 isn't
immediately casted to an integer type, not because of
any of the operators.
 
E

ena8t8si

pete said:
Jordan said:
2006-08-21 said:
Dave Thompson wrote:

pete wrote:

int main(void)
{
char a[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char b[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];
char c[(size_t)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3];

(to allocate enough space for a conversion to decimal)

A question: is that valid C89, too? gcc accepts it
with -std=c89 -pedantic-errors,
but I was under the impression that integer
constant expressions could not contain floating point arithmetic.

I think you're right
and it's not allowed/guaranteed by the Standard.

I disagree.
The "floating constant" part of the above expression,
is the immediate operand of cast.

An expression involving a floating-point
arithmetic operator (especially
one involving the division operator) is _not_ a "constant".

Then I guess I'll just have to change it to division by 3 instead.

Using ... * 16u / 53 ... keeps the expression in integer and
also provides a better approximation than 3.3.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,228
Latest member
MikeMichal

Latest Threads

Top