tags:

views:

507

answers:

4

So I use sprintf

sprintf(buffer, "%f|%f|%f|%f|%f|%f|%d|%f|%d", x, y, z, u, v, w, nID, dDistance, nConfig);

But when I print the buffer I get the 2 last parameters wrong, they are lets suppose to be 35.0000 and 0 and in the string they are 0.00000 and 10332430 and my buffer is long enough and all the other parameters are good in the string

Any idea? Is there a length limit to sprintf or something?

I checked the types of all the numbers and they are right, but what seems to be the problem is the dDistance. When I remove it from the sprint, the nConfig gets the right value in the string, but when I remove nConfig, dDistance still doesn't get the right value. I checked and dDistance is a double. Any idea?

Since people don't seem to believe me I did this :

char test[255]={0};
int test1 = 2;
double test2=35.00;
int test3 = 0;

sprintf(test,"%d|%f|%d",test1,test2,test3);

and I get this in my string:

2|0.000000|1078034432
+4  A: 

I'd check to make sure your argument types match up with your format string elements. Trying to display a double as an integer type (%d) or vice versa can give you strange output.

John at CashCommons
+2  A: 

Are you sure your data types match your format spec?

Try printing out your data, that is, create a printf with the same format and see what happens that is:

printf("%f|%f|%f|%f|%f|%f|%d|%f|%d", x, y, z, u, v, w, nID,dDistance, nConfig);

Try using streams, for example

stringstream ss;

ss << x << "|" << y << "|" << z << "|" << u << "|" << v << "|" << w << "|"
   << nID << "|"<< dDistance << "|"<< nConfig;

string s = ss.str();

and then do something with s;

Liz Albin
They match but then when I try and swap lets say the first one with the last one and swap the %f with the %d as well I get the right string.
Apoc
I don't understand what you mean, explain further please?
Liz Albin
If I swap x with nconfig and put %f and %d to their respective places, I get the right string.
Apoc
so are you saying that this statement works?printf("%d|%f|%f|%f|%f|%f|%d|%f|%f", nConfig, y, z, u, v, w, nID,dDistance, x);because /that/ makes it sound like you've got a typo somewhere
Liz Albin
A: 

What size are long and int?

If nID is a long being printed with an 'int' format and sizeof(int) != sizeof(long) then you get misaligned data access (in the sense that the alignment is not correct) from there on.

Which compiler are you using? GCC should diagnose the problem without difficulty if that is the trouble. Similarly, if nID is a 'long long', you could have problems.


To answer your question - yes, there is an lower-bound on the upper-limit of the length of string that sprintf() must be able to handle. The number is 509 for C89 systems, and 4095 for C99 systems.

To be precise, C99 says (fprintf(), section §7.19.6.1, para 15):

The number of characters that can be produced by any single conversion shall be at least 4095.

There is no further qualification on sprintf().


With fixed version of amended example converted into compilable code:

#include <stdio.h>
int main(void)
{
    char  test[255] = {0};
    int    test1 = 2;
    double test2 = 35.00;
    int    test3 = 0;
    sprintf(test, "%d|%f|%d", test1, test2, test3);
    puts(test);
    return(0);
}

I get the output I would expect:

2|35.000000|0

To be getting the output you show, you have to be working with a very weird setup.

  • What platform are you on?

The behaviour you are showing indicates that the sprintf() function you are using is confused about the alignment or size of something. Do you have a prototype in scope - that is, have you #included <stdio.h>? With GCC, I get all sorts of warnings when I omit the header:

x.c: In function ‘main’:
x.c:8: warning: implicit declaration of function ‘sprintf’
x.c:8: warning: incompatible implicit declaration of built-in function ‘sprintf’
x.c:9: warning: implicit declaration of function ‘puts’

But even with test2 redefined as a float I get the correct result.

If I change test2 into a long double, then I get a different set of warnings and a different result:

x.c: In function ‘main’:
x.c:8: warning: implicit declaration of function ‘sprintf’
x.c:8: warning: incompatible implicit declaration of built-in function ‘sprintf’
x.c:8: warning: format ‘%f’ expects type ‘double’, but argument 4 has type ‘long double’
x.c:9: warning: implicit declaration of function ‘puts’

2|0.000000|0

This is closer to what you are seeing, though far from identical.

Since we don't have the platform information, I'm suspicious that you are working with a truly ancient (or do I mean buggy?) version of C. But I'm still at something of a loss to see how you get what you show - unless you're on a big-endian machine (I'm testing on Intel Mac with MacOS X 10.6.2) ...pause... on a SPARC machine running Solaris 10, without #include <stdio.h> and with long double test2 = 35.0;, I get:

gcc -O x.c -o x && ./x 
x.c: In function 'main':
x.c:8: warning: incompatible implicit declaration of built-in function 'sprintf'
2|-22446048024026502740613283801712842727785152907992454451420278635613183447049251888877319095301502091725503415850736723945766334416305449970423980980099172087880564051243997662107950451281495566975073444407658980167407319222477077473080454782593800009947058951029590025152409694784570786541673131117073399808.000000|0

That's different; it also generates 321 characters of output, so there's a buffer overflow in there - it is better to use 'snprintf()' to prevent that from occurring. When things are declared properly, of course, I get the expected result.

So, can you post compilable code that shows your problem, instead of a snippet that does not? And can you identify your platform - machine type, operating system version, compiler version (and maybe C library version)?

Jonathan Leffler
A: 

Is dDistance of type double? It looks like your %f is only grabbing four bytes of a double and then the next four bytes are treated as an integer, the real integer value is then ignored.

This question is tagged C++; are you able to use std::ostringstream which would eliminate any possible problems with the conversion string?

Mark B
Everything is a double except for nID and nConfig which are int.
Apoc
From your latest update, if you convert 35.0 to an IEEE double you get bit pattern 0x107803443200000000. If you take just the upper four bytes, it just happens to convert in integer form to 1078034432 (this only applies if your architecture is little endian). In your test program try %lf instead of %f to see if your library maybe isn't handling the %f-to-double format correctly.
Mark B