sprintf and floats

I thought this would be easy. I have 2 integers that I cast to floats and divide, I then try to format the output with sprintf..

char* str = " ";
int i1 = 5;
int i2 = 10;
float f = ((float)i1)/((float)i2);
sprintf(str, "%f%c", f, 0x00);

I get a question mark. Why? I have tried doubles as well, same thing. The float value is correct, if I do a print to Serial and monitor the output it works fine.

What I actually want is %5.1f but it just doesn't work.

What am I doing wrong?

sprintf does not support floats. You have to use dtostrf to first convert the value to a character-array.

The problem is not sprintf() but really the IDE.
AVR libc does have floating support for xxprintf() routines.
But because floating point takes a considerable amount of code space,
there are multiple versions of the xxprintf() routines.
The default version of sprintf() does not support floating point.
You could link in the floating point version, but the IDE has the linker
options hard coded in the JAVA code.
Because of this you are SOL using the Arduino IDE.
However, you could leave the standard Arduino IDE behind and switch
over to mpide.
mpide allows you to set the compiler and linker options so you
could set the options you need using that version of the "arduino" IDE.
mpide is not currently up to 1.0 functionality though.

See this for some information about the avr-gcc linker options:
http://winavr.scienceprog.com/comment/28

If all you need is something as simple as %5.1f then you could create the two parts
separately using integer math.
It would be smaller as the guts under sprintf() eats up about 1.8k or
so of code.

--- bill

Thanks for the help, thought I was going nuts :slight_smile:

Hi!

The same thing was bugging me for a day or so; :cold_sweat: not being able to inject the proper linker options to link against the float enabled versions of the necessary libs.

I ended up building 2 environments (both solving the problem): :wink:

  • setting up an Eclipse environment with the Arduino plugin (where AVR toolchain, so Linker options can be fine-tuned) /working on a larger project, it was a must, anyway/
  • forking and patching the Arduino IDE to take additional preferences and call the avr-gcc accordingly /for simpler sketches it is the faster option, also the Serial Monitor is lacking from the Eclipse project/

more details at: http://srejbi.info/posts/16_arduino-printf-scanf-floats
source: GitHub - srejbi/Arduino: open-source electronics prototyping platform

indeed, the binary size gets larger /more or less, depending on the optimization options passed/, but I wonder how larger the binary would get if I reimplemented printf/scanf with some 'proprietary' hacks to get the float values printed properly (from argument lists, especially)... ]:smiley:

If you install the streaming library, you can print floats easily enough.

#include <Streaming.h>

void setup ()
  {
  float foo;
  Serial.begin (115200);

  Serial << foo << endl;
  }

does the streaming lib also support e.g. "%5.1f" formatting?

robtillaart:
does the streaming lib also support e.g. "%5.1f" formatting?

No, it is quite basic. If you want %f and %g with all the options you have to diddle things around to use the proper version of printf() or use dtostre() or dtostrf() and manipulate the string result.
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga6c140bdd3b9bd740a1490137317caa44

A good discussion of the full versus training wheels version of sprintf() are set out here:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

Here's a quick and dirty function to convert a float to a formatted ASCII string:

/*----------------------------------------------------------------------------*/
/* f2a() - convert x to string with l places left of decimal point and r on   */
/*         the right. Returns a pointer to the string in an internal buffer.  */
/*         Written by Morris Dovey (mrdovey@iedu.com)                         */
/*----------------------------------------------------------------------------*/
char *f2a(float x,unsigned char l,unsigned char r)
{  static unsigned char buffer[16];
   unsigned char digits=0,*p,q=r,sign=x<0;
   float fract,round;
   unsigned long whole;

   if (sign) x = -x;
   for (round=0.5; q--; round/=10);
   x += round;
   whole = x;
   fract = x - whole;
   do ++digits; while (whole /= 10);
   whole = x;
   digits += sign;
   if (l > digits) digits = l;
   p = buffer + digits;
   do *--p = whole % 10 + '0'; while (whole /= 10);
   if (sign) *--p = '-';
   while (p != buffer) *--p = ' ';
   p = buffer + digits;
   *p++ = '.';
   while (r--)
   {  fract *= 10;
      whole = fract;
      fract -= whole;
      *p++ = whole + '0';
   }
   *p = '\0';
   return buffer;
}