473,385 Members | 1,606 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

sprintf

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
15 3495
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
"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
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
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
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
"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
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

<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
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
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
@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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: Yodai | last post by:
Hi all.... I have a little problem that's driving me nuts. I can't seem to make any sense of it. I have this small webserver that substitutes some data from a page when finds a substitution...
3
by: huey_jiang | last post by:
Hi All, I am trying to figure out a right syntax to convert an integer array into hex array. sprintf worked for me on doing single integer: int i, Iarray, n=15; char buf; sprintf(buf,...
6
by: jt | last post by:
I need to produce 1 character array from 3 others. I tried sprintf and it terminates on the first 0, null, 0x00 it sees in tmp data. All 3 args print out nice by themselves. By trying to make...
1
by: jimjim | last post by:
Hello, I was wondering about the implications of giving as an argument to sprintf a different data type from the one specified in the format argument. This type of question along with some...
2
by: aap | last post by:
I have the following code #define MAX 32 struct A { char carr; int iarr; int i; }; void main() {
9
by: Neal Barney | last post by:
I have a C program which runs on a device using a Zilog Z180 microprocessor. While it can address 1MB of RAM, it can only address 64KB at any given time. And of that only 16KB can be used for...
12
by: Henryk | last post by:
Hey there, I have some problems with the following code snippet on a Virtex-4 PowerPC with a GCC based compiler char chData; sprintf(&chData, "%+05.0f", -0.038f); --I get "-000" ???...
5
by: Dave | last post by:
Hi, In awk I can do this: var1="x"; temp = sprintf("Variable 1: %s Variable 2: %%s", var1); # now the value of temp is "Variable 1: x Variable 2: %s" var2="y"; printf(temp,var2);
3
by: google | last post by:
Consider the following code: char str; char str2; strcpy(str, "%alfa% %beta% d%100%d %gamma% %delta%"); printf("printf: "); printf("1%s2", str); printf("\nsprintf: "); sprintf(str2, "1%s2",...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.