Odd sprintf behaviour

C and C++ will give you the same error.

The "error" is compounded by the order you are doing your sprintfs. If you were to swap them around you would get very different results.

The first sprintf is placing the data in the first array fine, but the terminating null character is ending up as the first character of the second array. The second sprintf is then overwriting that null character.

Swapping them around would give you the first array looking perfectly fine, but the second array would appear empty, which would be just as confusing :wink:

KirAsh4:
Can anyone explain to me why it appears that the 'currTime' variable gets tacked onto the end of the 'currDate' one? If I just output 'currDate', I get:Current Date: 2013/01/13Current Time: 23:32:27

Why's that?

You need to have cr/lf sequences in your sprintf format strings. Example:

sprintf(buffer, "Hello, my name is %s", "Roger");
Serial.print(buffer);
sprintf(buffer, "I am %d years old", 56);
Serial.print(buffer);

...produces:

Hello, my name is RogerI am 56 years old

However, this:

sprintf(buffer, "Hello, my name is %s\r\n", "Roger");
Serial.print(buffer);
sprintf(buffer, "I am %d years old\r\n", 56);
Serial.print(buffer);

...produces:

Hello, my name is Roger
I am 56 years old

The "\r" is a "return" (carriage return - 0x0D or 13 decimal) and "\n" is a "newline" (moves to the next line - 0x0A or 10 decimal).

NOTE that using %f (floating point) in sprintf will fail (it will print a question mark "?" instead of the number) because the floating point code for sprintf and sscanf has been removed from the "libc.a" library in order to make compiled sketches smaller. If you would like to add the ability to use floating point in sprintf and sscanf, replace your "pde.jar" file with the one attached. This version adds an option to turn on or off floating point support and save the setting in your "preferences.txt" file. Simply rename your "pde.jar" file to "pde.bak", then unzip the new on in place.

You will see a new checkbox option in the "Preferences" menu called "Enable floating point support". Turn this on or off as needed. If it's on, it will make your compiled sketches about 1.5K larger (but then floating point will actually work!) :slight_smile:

(edit): This pde.jar file is for IDE version 1.0.0 to 1.0.3, NOT for the new 1.5.1 version.

Hope this helps.

pde.zip (748 KB)

He used Serial.println() to print both. That adds cr/lf.

Yeah, I used println().

And rather than adding the additional 1.5K to my sketches to allow for floating points, I did it like this:

    float cTemp = Clock.getTemperature();
    int cTemp1 = (cTemp - (int)cTemp) * 100;
    sprintf(currTemp, "Current Temp: %0d.%d C", (int)cTemp, cTemp1);

Suppose cTemp is 12.07. What gets put in currTemp?

KirAsh4:
Yeah, I used println().

And rather than adding the additional 1.5K to my sketches to allow for floating points, I did it like this:

    float cTemp = Clock.getTemperature();

int cTemp1 = (cTemp - (int)cTemp) * 100;
    sprintf(currTemp, "Current Temp: %0d.%d C", (int)cTemp, cTemp1);

Is your sketch right at the edge of not having enough memory to run in, or do you just feel better having unused flash? :slight_smile:

Note that the new PDE.JAR file allows you to enable or disable the floating point support. If you want to use floating point support (and use an extra 1.5K) turn on FP support, If you are against the wall for memory, turn FP off.

In any case, it's better to HAVE the option than not... agreed?

PaulS:
Suppose cTemp is 12.07. What gets put in currTemp?

LOL! Good point... never thought about that.

I suppose a few more lines of code to check for "cTemp1 < 10" and then adding an ascii 0 kludge is SO much better than using "printf (%5.2f)" :slight_smile:

PaulS:
Suppose cTemp is 12.07. What gets put in currTemp?

It won't be. The temperature reading is always in .25 increments, thus 12.00, 12.25, 12.50, or 12.75.

And I never claimed that method to be perfect. I just choose it because I know the incoming temperature readings.

Krupski:
Is your sketch right at the edge of not having enough memory to run in, or do you just feel better having unused flash? :slight_smile:

Ultimately, quite possible. Right now I'm hovering around 29-30K ... however, I also have not done any optimization to the code yet. I'm in the R&D stage and just writing code to get the result I want. Once I have things working, I will go through and clean it up, at which point I may very well have plenty of room.

GoForSmoke:
He used Serial.println() to print both. That adds cr/lf.

Yeah, that works, but personally I prefer to use only Serial.print(), then put the "\r\n" in the string if I want a new line. It's easier for me to keep it all straight in my mind.

(actually, I create a "stdin" and "stdout" pointer to the serial device, then use "printf()", but that's a whole 'nuther story!) :slight_smile:

Floating Point is slow on non-FPU chips. Why use it if you don't really need it?
And in general, you don't if you can handle fixed-point integers and understand what units are.

Suppose cTemp is 12.07. What gets put in currTemp?

will this do?

sprintf(currTemp, "Current Temp: %0d.%2d C", (int)cTemp, cTemp1);

and yeah, I was waiting and sure he'd spot it. Guess I owe someone a buck.

KirAsh4:
Ultimately, quite possible. Right now I'm hovering around 29-30K

Well, if you are running out of memory then of course using an extra 1.5K would be a bad thing for sure.

My "slightly sarcastic" comment was really directed to those who write sketches that end up being 9K, then they complain about the extra 1.5K of memory that the floating point code uses and instead use tons of "Serial.print()" calls in series to build up one line that could have been much more easily done with a simply "sprintf()".

The Arduino IDE and programming "language" is certainly wonderful for rank beginners, but it doesn't take long for a user to outgrow the hand-holding and wanting to start writing code the "right way".

GoForSmoke:
Floating Point is slow on non-FPU chips. Why use it if you don't really need it?
And in general, you don't if you can handle fixed-point integers and understand what units are.

If I want to print something like "Temperature: 20.4 C" using "%4.2f", do I REALLY care about the few extra microseconds the code takes to execute?

will this do?
Code:
sprintf(currTemp, "Current Temp: %0d.%2d C", (int)cTemp, cTemp1);

No. :wink:

Krupski:
My "slightly sarcastic" comment was really directed to those who write sketches that end up being 9K, then they complain about the extra 1.5K of memory that the floating point code uses and instead use tons of "Serial.print()" calls in series to build up one line that could have been much more easily done with a simply "sprintf()".

The Arduino IDE and programming "language" is certainly wonderful for rank beginners, but it doesn't take long for a user to outgrow the hand-holding and wanting to start writing code the "right way".

I'm already blowing away the bootloader to reclaim the 2K it takes. :slight_smile: But yes, eventually I will rewrite the whole thing.

GoForSmoke:
will this do?

sprintf(currTemp, "Current Temp: %0d.%2d C", (int)cTemp, cTemp1);

Based on his example, no that won't. It will translate 12.07 into 12 and 7, as opposed to 12 and 07. The end result will be 12.7C instead of 12.07C. And I'm well aware of that, however, as I pointed out, I know what the incoming temperature reading looks like, it will never have a .0x ...

Now, that doesn't necessarily fix the next conversion, which is computing the F value. If that ends with a .0x, I could have issues.

KirAsh4:
I'm already blowing away the bootloader to reclaim the 2K it takes. :slight_smile: But yes, eventually I will rewrite the whole thing.

You said you were nearing 30K code size which to me implied an Arduino UNO or similar 32K board.

The UNO has a 1/2K (512 byte) bootloader. If you gained 2K by doing away with the bootloader, what board do you have? It sounds like a MEGA2560 (if so, then you have 256K of flash, not 32).

I'm confused.

It's been a long damned time since I used sprintf regularly and I know there is a format string to put the leading zero in but I guess I'm as lazy as anyone else that didn't look it up. Difference being, none of my code is waiting for it!

Krupski:
You said you were nearing 30K code size which to me implied an Arduino UNO or similar 32K board.

The UNO has a 1/2K (512 byte) bootloader. If you gained 2K by doing away with the bootloader, what board do you have? It sounds like a MEGA2560 (if so, then you have 256K of flash, not 32).

Yeah sorry, no. I'm still used to the old bootloaders taking up 2K worth of space. You're right, it's just that 512 space. I'm not using any specific board, I'm designing my own based on the 328p.

Either way, the end result of all of this is that a) for now, using the method I choose works for the time being, and b) once I rewrite it all and optimize it, I may very well have plenty of room to add floating point support (and watch 1.5K magically fly away.)

Krupski:

KirAsh4:
Can anyone explain to me why it appears that the 'currTime' variable gets tacked onto the end of the 'currDate' one? If I just output 'currDate', I get:Current Date: 2013/01/13Current Time: 23:32:27

Why's that?

You need to have cr/lf sequences in your sprintf format strings. Example:

sprintf(buffer, "Hello, my name is %s", "Roger");

Serial.print(buffer);
sprintf(buffer, "I am %d years old", 56);
Serial.print(buffer);




...produces:

Hello, my name is RogerI am 56 years old

However, this:



sprintf(buffer, "Hello, my name is %s\r\n", "Roger");
Serial.print(buffer);
sprintf(buffer, "I am %d years old\r\n", 56);
Serial.print(buffer);




...produces:

Hello, my name is Roger
I am 56 years old

The "\r" is a "return" (carriage return - 0x0D or 13 decimal) and "\n" is a "newline" (moves to the next line - 0x0A or 10 decimal).

Nope, about 23 foot wide of the mark.

See my answer just before yours:

The first sprintf is placing the data in the first array fine, but the terminating null character is ending up as the first character of the second array. The second sprintf is then overwriting that null character.