By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
431,983 Members | 1,717 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 431,983 IT Pros & Developers. It's quick & easy.

sprintf

P: n/a
Hello,

I'm working in a quite large system that has some limitations. One of
those is that I can't use printf() to get an output on a screen. I'm
forced to use a special function, let's call it PrintOnConsole(), to get
the output on a console. The problem with PrintOnConsole() is that it
only takes strings as input arguments. On the other hand, I'm free to
use sprintf(), so I can convert everything I want to print into a string
and then forward that string to PrintOnConsole().

My problem now is that I don't know how many characters sprintf() will
put in the buffer provided as first input argument.
Here is a code example:

/*-------------------- Begin --------------------------*/

#include <stdio.h>

/* This is just a dummy function, which I don't have access to in reality */
float GimmeAFloat(void)
{
return 34.2;
}

/* This is just a dummy function, which I don't have access to in reality */
void PrintOnConsole(char *string)
{
/* printf() is used here only for testing purposes. Itís not
available in reality in my system */
printf("%s", string);
}
int main(void)
{

float value;
char buf[25];

value = GimmeAFloat();

/* Pre check wanted here. If the value is too long I want to copy the
string ďThe value is too long\nĒ to buf instead. */

sprintf(buf, "This is my value: %f\n", value);

PrintOnConsole(buf);

return 0;
}

/*--------------------- End -------------------------*/
Is there any elegant way to do some kind of pre-check how many
characters sprintf() would need?
Iíve used float in this example, but the question is more general. Iíd
like to be able to print int, double, long, etc.
I know that sprintf() returns the number of characters printed, but
thatís too late (Iíve already called sprintf() by then).
(It would be nice if it was possible to call sprintf() with NULL as
first argument just to investigate the return value.)

A bonus question: In the code above everything looks OK for me, the
string provided to sprintf() is 18 characters long plus 4 characters for
the float value plus 1 linefeed character plus the terminating null
character makes all in all 24 characters. The output, however, shows:

This is my value: 34.200001
Why isnít
This is my value: 34.2
printed?
Thanks in advance,
Krister
Jun 14 '07 #1
Share this Question
Share on Google+
15 Replies


P: n/a
In article <f4**********@news.al.sw.ericsson.se>,
kr*****@kalleanka.se <kr*****@kalleanka.sewrote:
>Is there any elegant way to do some kind of pre-check how many
characters sprintf() would need?
See if you have snprintf() [Notice the extra 'n']. If you do and you
provide it with a buffer of size 0, it will return the number of
characters that would be needed to output the arguments, but without
actually outputing anything.
--
Okay, buzzwords only. Two syllables, tops. -- Laurie Anderson
Jun 14 '07 #2

P: n/a
"kr*****@kalleanka.se" <kr*****@kalleanka.sewrites:
I'm working in a quite large system that has some limitations. One of
those is that I can't use printf() to get an output on a screen. I'm
forced to use a special function, let's call it PrintOnConsole(), to
get the output on a console. The problem with PrintOnConsole() is that
it only takes strings as input arguments. On the other hand, I'm free
to use sprintf(), so I can convert everything I want to print into a
string and then forward that string to PrintOnConsole().

My problem now is that I don't know how many characters sprintf() will
put in the buffer provided as first input argument.
Does your implementation have snprintf? snprintf allows you to
specify the maximum number of characters to write to the output
string. If your buffer is too small, you can then allocate a
larger one and try again.
--
Ben Pfaff
http://benpfaff.org
Jun 14 '07 #3

P: n/a
On Jun 14, 9:56 pm, "kris...@kalleanka.se" <kris...@kalleanka.se>
wrote:
Hello,

I'm working in a quite large system that has some limitations. One of
those is that I can't use printf() to get an output on a screen. I'm
forced to use a special function, let's call it PrintOnConsole(), to get
the output on a console. The problem with PrintOnConsole() is that it
only takes strings as input arguments. On the other hand, I'm free to
use sprintf(), so I can convert everything I want to print into a string
and then forward that string to PrintOnConsole().

My problem now is that I don't know how many characters sprintf() will
put in the buffer provided as first input argument.
Here is a code example:

/*-------------------- Begin --------------------------*/

#include <stdio.h>

/* This is just a dummy function, which I don't have access to in reality */
float GimmeAFloat(void)
{
return 34.2;

}

/* This is just a dummy function, which I don't have access to in reality */
void PrintOnConsole(char *string)
{
/* printf() is used here only for testing purposes. It's not
available in reality in my system */
printf("%s", string);

}

int main(void)
{

float value;
char buf[25];

value = GimmeAFloat();

/* Pre check wanted here. If the value is too long I want to copy the
string "The value is too long\n" to buf instead. */

sprintf(buf, "This is my value: %f\n", value);

PrintOnConsole(buf);

return 0;

}

/*--------------------- End -------------------------*/

Is there any elegant way to do some kind of pre-check how many
characters sprintf() would need?
No, portably there is no way to count the number of characters that
could be output on a target.
I've used float in this example, but the question is more general. I'd
like to be able to print int, double, long, etc.
I know that sprintf() returns the number of characters printed, but
that's too late (I've already called sprintf() by then).
(It would be nice if it was possible to call sprintf() with NULL as
first argument just to investigate the return value.)
sprintf is as dangerous as gets().
Better use snprintf().
>
A bonus question: In the code above everything looks OK for me, the
string provided to sprintf() is 18 characters long plus 4 characters for
the float value plus 1 linefeed character plus the terminating null
character makes all in all 24 characters. The output, however, shows:

This is my value: 34.200001

Why isn't
This is my value: 34.2
printed?
Thats the problem with floating point numbers When you use
return 34.2;
there is a conversion from double to float.
Change the return statement to
return 34.2f;
>
Thanks in advance,
Krister

Jun 14 '07 #4

P: n/a
kr*****@kalleanka.se wrote:

| Is there any elegant way to do some kind of pre-check how many
| characters sprintf() would need?

Of course there is. You already know how many places you intend to
print to the right of the decimal point. You can use base ten
logarithms to determine the number of places needed to the left of the
decimal point.

You'll need minimal logic to deal with negative values and sign,
padding spaces, etc., but that's not difficult.

HTH :-)

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto/
Jun 14 '07 #5

P: n/a
On Thu, 14 Jun 2007 18:56:23 +0200, "kr*****@kalleanka.se"
<kr*****@kalleanka.sewrote:
>Hello,

I'm working in a quite large system that has some limitations. One of
those is that I can't use printf() to get an output on a screen. I'm
forced to use a special function, let's call it PrintOnConsole(), to get
the output on a console. The problem with PrintOnConsole() is that it
only takes strings as input arguments. On the other hand, I'm free to
use sprintf(), so I can convert everything I want to print into a string
and then forward that string to PrintOnConsole().

My problem now is that I don't know how many characters sprintf() will
put in the buffer provided as first input argument.
Here is a code example:

/*-------------------- Begin --------------------------*/

#include <stdio.h>

/* This is just a dummy function, which I don't have access to in reality */
float GimmeAFloat(void)
{
return 34.2;
}

/* This is just a dummy function, which I don't have access to in reality */
void PrintOnConsole(char *string)
{
/* printf() is used here only for testing purposes. Itís not
available in reality in my system */
printf("%s", string);
}
int main(void)
{

float value;
char buf[25];

value = GimmeAFloat();

/* Pre check wanted here. If the value is too long I want to copy the
string ďThe value is too long\nĒ to buf instead. */

sprintf(buf, "This is my value: %f\n", value);

PrintOnConsole(buf);

return 0;
}

/*--------------------- End -------------------------*/
Is there any elegant way to do some kind of pre-check how many
characters sprintf() would need?
Iíve used float in this example, but the question is more general. Iíd
like to be able to print int, double, long, etc.
I know that sprintf() returns the number of characters printed, but
thatís too late (Iíve already called sprintf() by then).
(It would be nice if it was possible to call sprintf() with NULL as
first argument just to investigate the return value.)

A bonus question: In the code above everything looks OK for me, the
string provided to sprintf() is 18 characters long plus 4 characters for
the float value plus 1 linefeed character plus the terminating null
character makes all in all 24 characters. The output, however, shows:

This is my value: 34.200001
Why isnít
This is my value: 34.2
printed?
How do you think 34.2 is represented in binary? 34.5 is easy as is
34.25 or 34.125 but think about 34.2. How is sprintf to know that
there is only one significant digit after the decimal point? For that
matter, do you know after each call to GimmeAFloat?

But you can write code that handles most cases:

int sign = value<0; will tell you if you need space for a '-'.

int dig = 1+log10(fabs(value)); will tell you how many digits
before the decimal point, if any. Based on this value, you can decide
to use either %f or %e for floating point values (which are always
passed to sprintf as doubles). You can also use this to compute how
many digits you want after the decimal point (call this value dec).

You can then use these values in your pre-check.

If you decide to print, sprintf will let you specify both
minimum field width (apparently not your concern here) and precision
as *. This will cause the function to extract the actual values to
use in the format conversion from arguments which you can compute

For your example, sign would be 0, dig would be 2, and you could
compute dec as 1. You pre-check would be
if (sign+dig+1+dec < your_max)
and you would call sprintf with something like
sprintf(buf, "This is my value: %.*f\n", dec, value);

Remove del for email
Jun 14 '07 #6

P: n/a
"Morris Dovey" <mr*****@iedu.comwrites:
kr*****@kalleanka.se wrote:

| Is there any elegant way to do some kind of pre-check how many
| characters sprintf() would need?

Of course there is. You already know how many places you intend to
print to the right of the decimal point. You can use base ten
logarithms to determine the number of places needed to the left of the
decimal point.
If that's the desired approach then you could just allocate space
for the maximum possibly needed digits using DBL_MAX_10_EXP as a
basis, I'd guess.
--
Ben Pfaff
http://benpfaff.org
Jun 14 '07 #7

P: n/a
CryptiqueGuy <SR**********@gmail.comwrites:
On Jun 14, 9:56 pm, "kris...@kalleanka.se" <kris...@kalleanka.se>
wrote:
[...]
sprintf is as dangerous as gets().
No, it really isn't. gets() is inherently unsafe *unless* you have
control over what input will appear on stdin (which you usually
don't). sprintf() can be used safely if you're sufficiently careful
with the format string, the arguments, and the target string, all of
which are under the control of your program and can be checked before
attempting the call. (But checking in general is about as difficult as
implementing sprintf itself.)
Better use snprintf().
Agreed, if it's available.

[...]
>This is my value: 34.200001

Why isn't
This is my value: 34.2
printed?
Thats the problem with floating point numbers
Yes.
When you use
return 34.2;
there is a conversion from double to float.
But that's not the reason.
Change the return statement to
return 34.2f;
That's unlikely to help. The value 34.2 is not exactly representable
in either float or double (or long double). Using a larger
floating-point type (it's common to use double rather than float) will
make the error smaller, but not eliminate it.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 14 '07 #8

P: n/a

<kr*****@kalleanka.sewrote in message
news:f4**********@news.al.sw.ericsson.se...
Hello,

I'm working in a quite large system that has some limitations. One of
those is that I can't use printf() to get an output on a screen. I'm
forced to use a special function, let's call it PrintOnConsole(), to get
the output on a console. The problem with PrintOnConsole() is that it only
takes strings as input arguments. On the other hand, I'm free to use
sprintf(), so I can convert everything I want to print into a string and
then forward that string to PrintOnConsole().

My problem now is that I don't know how many characters sprintf() will put
in the buffer provided as first input argument.
Here is a code example:

/*-------------------- Begin --------------------------*/

#include <stdio.h>

/* This is just a dummy function, which I don't have access to in reality
*/
float GimmeAFloat(void)
{
return 34.2;
}

/* This is just a dummy function, which I don't have access to in reality
*/
void PrintOnConsole(char *string)
{
/* printf() is used here only for testing purposes. Itís not available
in reality in my system */
printf("%s", string);
}
int main(void)
{

float value;
char buf[25];

value = GimmeAFloat();

/* Pre check wanted here. If the value is too long I want to copy the
string ďThe value is too long\nĒ to buf instead. */

sprintf(buf, "This is my value: %f\n", value);

PrintOnConsole(buf);

return 0;
}

/*--------------------- End -------------------------*/
Is there any elegant way to do some kind of pre-check how many characters
sprintf() would need?
Iíve used float in this example, but the question is more general. Iíd
like to be able to print int, double, long, etc.
I know that sprintf() returns the number of characters printed, but thatís
too late (Iíve already called sprintf() by then).
(It would be nice if it was possible to call sprintf() with NULL as first
argument just to investigate the return value.)

A bonus question: In the code above everything looks OK for me, the string
provided to sprintf() is 18 characters long plus 4 characters for the
float value plus 1 linefeed character plus the terminating null character
makes all in all 24 characters. The output, however, shows:

This is my value: 34.200001
Why isnít
This is my value: 34.2
printed?
Thanks in advance,
Krister
You want vsprintf.

void myprintf(char *fmt, ...)
{
/* go through fmt looking for % signs. If you have a string, pull it out
and calculate the length. If an number, make sure the field width isn't
excessive, and add a few bytes. Then add a few more bytes for luck, malloc
it and call vsprintf, the call the console routine with the strign you
created */
}
Jun 14 '07 #9

P: n/a
On Jun 15, 6:30 am, Keith Thompson <k...@mib.orgwrote:
CryptiqueGuy <SRRajesh1...@gmail.comwrites:
Better use snprintf().

Agreed, if it's available.
If it isn't, then you can use one of the public-domain
implementations of it that are out there.

Jun 14 '07 #10

P: n/a
On Jun 14, 11:30 pm, Keith Thompson <k...@mib.orgwrote:
CryptiqueGuy <SRRajesh1...@gmail.comwrites:
On Jun 14, 9:56 pm, "kris...@kalleanka.se" <kris...@kalleanka.se>
wrote:
[...]
sprintf is as dangerous as gets().

No, it really isn't. gets() is inherently unsafe *unless* you have
control over what input will appear on stdin (which you usually
don't). sprintf() can be used safely if you're sufficiently careful
with the format string, the arguments, and the target string, all of
which are under the control of your program and can be checked before
attempting the call. (But checking in general is about as difficult as
implementing sprintf itself.)
I would rather involve myself in writing "smart codes" using snprint
than involve in doing all sorts of "avoidable" (avoidable using
snprintf) analyses to ensure that my sprintf does not produce UB.
But if OP has to use some archaic C90 compiler, then of course, he has
to do these analyses to ensure that his sprintf does not produce UB.

I agree that sprintf is not as bad as gets.
But both are bad!
They differ only in their degree of badness.

It is something like stating,
"The ruffian sprintf is not as cruel as the pirate leader gets" .;)

The ruffian treats you well as long as you treat it well!
The pirate leader is completely out of your control!
Everything is a matter of sheer luck!
Better use snprintf().

Agreed, if it's available.

[...]
This is my value: 34.200001
Why isn't
This is my value: 34.2
printed?
Thats the problem with floating point numbers

Yes.
When you use
return 34.2;
there is a conversion from double to float.

But that's not the reason.
In most of the cases and in this particular case, that is not the
reason. I agree.
>
Change the return statement to
return 34.2f;

That's unlikely to help.
In this case of printing the value, I agree again.
But this is a good practice. What if OP wants to do some floating
point calculation, using 34.2f is "more likely" (but definitely not
guaranteed) to produce the result he intended, rather than using plain
34.2, in which case there is a demotion from double to float,
resulting in loss of precision.
>The value 34.2 is not exactly representable
in either float or double (or long double). Using a larger
floating-point type (it's common to use double rather than float) will
make the error smaller, but not eliminate it.

--
Keith Thompson (The_Other_Keith) k...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Jun 15 '07 #11

P: n/a
@Keith Thompson <k...@mib.org>

I apologise for quoting your signature in my previous post. I didn't
notice that. It was quite unintentional. Sorry.

Jun 15 '07 #12

P: n/a
Walter Roberson wrote:
In article <f4**********@news.al.sw.ericsson.se>,
kr*****@kalleanka.se <kr*****@kalleanka.sewrote:
>Is there any elegant way to do some kind of pre-check how many
characters sprintf() would need?

See if you have snprintf() [Notice the extra 'n']. If you do and you
provide it with a buffer of size 0, it will return the number of
characters that would be needed to output the arguments, but without
actually outputing anything.
Thank you (and all others who have replied) very much. This was just the
nice and elegant solution I was dreaming of; I didnít know snprintf()
existed.
However, I did a quick test using 0 as the second argument to snprintf()
and got -1 returned from snprintf().
So I looked in the man page which says:

The snprintf() function returns the number of characters
formatted, that is, the number of characters that would have
been written to the buffer if it were large enough. If the
value of n is 0 on a call to snprintf(), an unspecified
value less than 1 is returned.

I guess you meant that I should use 1 instead of 0. That also means that
I need to provide a buffer that can hold (at least) one character,
namely the null character.
Jun 15 '07 #13

P: n/a
On Fri, 15 Jun 2007 16:53:46 +0200, "kr*****@kalleanka.se"
<kr*****@kalleanka.sewrote:
>Walter Roberson wrote:
>In article <f4**********@news.al.sw.ericsson.se>,
kr*****@kalleanka.se <kr*****@kalleanka.sewrote:
>>Is there any elegant way to do some kind of pre-check how many
characters sprintf() would need?

See if you have snprintf() [Notice the extra 'n']. If you do and you
provide it with a buffer of size 0, it will return the number of
characters that would be needed to output the arguments, but without
actually outputing anything.

Thank you (and all others who have replied) very much. This was just the
nice and elegant solution I was dreaming of; I didnít know snprintf()
existed.
However, I did a quick test using 0 as the second argument to snprintf()
and got -1 returned from snprintf().
So I looked in the man page which says:

The snprintf() function returns the number of characters
formatted, that is, the number of characters that would have
been written to the buffer if it were large enough. If the
value of n is 0 on a call to snprintf(), an unspecified
value less than 1 is returned.
It seems that your implementation isn't standards-conforming. Is it
possible that there's a compiler switch that affects this behavior?
The standard says (among other things):
"If n is zero, nothing is written, and s may be a null pointer."

A negative value should mean there was an encoding error.
>
I guess you meant that I should use 1 instead of 0. That also means that
I need to provide a buffer that can hold (at least) one character,
namely the null character.
Sounds like that may be a workaround.

--
Al Balmer
Sun City, AZ
Jun 15 '07 #14

P: n/a
On Fri, 15 Jun 2007 04:51:00 -0000, CryptiqueGuy
<SR**********@gmail.comwrote:
>I agree that sprintf is not as bad as gets.
But both are bad!
They differ only in their degree of badness.

It is something like stating,
"The ruffian sprintf is not as cruel as the pirate leader gets" .;)

The ruffian treats you well as long as you treat it well!
That sounds like a good description of the C language.

--
Al Balmer
Sun City, AZ
Jun 15 '07 #15

P: n/a
In article <f4**********@news.al.sw.ericsson.se>
kr*****@kalleanka.se <kr*****@kalleanka.sewrote:
>However, I did a quick test using 0 as the second argument to snprintf()
and got -1 returned from snprintf().
When I put snprintf() into 4.4BSD, I forgot to account for a
zero "buffer size" argument. This is fixed in the C99 standard
(and I fixed it in BSD/OS years ago), but others who picked up
my snprintf() might not have fixed it yet.
>So I looked in the man page which says:

The snprintf() function returns the number of characters
formatted, that is, the number of characters that would have
been written to the buffer if it were large enough. If the
value of n is 0 on a call to snprintf(), an unspecified
value less than 1 is returned.

I guess you meant that I should use 1 instead of 0. That also means that
I need to provide a buffer that can hold (at least) one character,
namely the null character.
This is a good-enough work-around, and is easy to code -- instead
of:

n = snprintf(NULL, 0, fmt, arg1, arg2, ..., argN);

you just need:

char dummy;
...
n = snprintf(&dummy, 1, fmt, arg1, arg2, ... argN);

(which is actually how I originally fixed my own implementation
internally -- it was easier to create a "dummy" variable than to
allow buf==NULL with size==0).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40į39.22'N, 111į50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Jun 15 '07 #16

This discussion thread is closed

Replies have been disabled for this discussion.