7

During a debugging session, I found out that snprintf is not working as expected when compiling the code with avr-gcc. The example code should simply convert the floating point value 3999.9f into its character representation.

Here is a minimal test case:

    int TestSnprintf(void)
    {
       const float inputValue = 3999.9f;
       /* Print with a fixed width of 6 characters (5 numbers and 1 dot).
       The buffer must have a length of 7, because snprintf appends a '\0' at the end. */
       char buf[7U] = {0, 0, 0, 0, 0, 0, 0};
       const uint8_t bufferSize = 7U;
       if(6 != snprintf(buf, bufferSize, "%06.1f", inputValue))
       {
          return -1;
       }
       if( buf[0] != '3'
            || buf[1] != '9'
            || buf[2] != '9'
            || buf[3] != '9'
            || buf[4] != '.'
            || buf[5] != '9'
            || buf[6] != '\0')
      {
          return -2;
      }

      return 0;
   }

   int main(void)
   {
     int retVal = TestSnprintf();
     return 0;
   }

Compiling this example code with avr-gcc and running it with Atmel Studio 7 gives a return value of -2. This means snprintf is not working.

What I have tried so far:

  • I tested the code on 32 and 64 bit Linux and it works as expected (TestSnprintf return the value 0).
  • I tested the code with Visual Studio 2015 and it worked as expected (TestSnprintf return the value 0).
  • The content of buf is

    buf[0] = 32;    
    buf[1] = 32;    
    buf[2] = 32;    
    buf[3] = 32;    
    buf[4] = 32;    
    buf[5] = 63;    
    buf[6] = 0;
    
  • The testing is performed on the device using the JTAG interface. I tried the simulator as well, with the same result.

  • No compiler optimization is activated. The code is compiled and debugged with -O0.

Here is a screenshot from the debugging session, that demonstrates that the return value is -2.

enter image description here

This demonstrates that buf is in scope during debugging: enter image description here

Question

What am I doing wrong?

SOLUTION

First of all thank you all very much for your help! As pointed out by @manilo the following linker options were missing:

-Wl,-u,vfprintf -lprintf_flt -lm
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
orbitcowboy
  • 1,438
  • 13
  • 25

2 Answers2

11

There are three different implementations of printf() (and friends). The default doesn't implement float output.

snprintf won't work without linking libprintf_flt.a (-lprintf_flt) and libm.a (-lm).

Also, according to the documentation, you have to add the linker options -Wl,-u,vfprintf (e.g. here).

The sequence of the linker flags is important: -Wl,-u,vfprintf -lprintf_flt -lm

manlio
  • 18,345
  • 14
  • 76
  • 126
-1

"Also note that by default the Arduino IDE does not set the AVR linker options to support floating point in the xxprintf() routines. So while that saves quite a bit of code space on the AVR builds, it means that printf() functions cannot be used for floating point output on the AVR. Floating support is included by default for the other processors." http://playground.arduino.cc/Main/Printf

jeton
  • 841
  • 12
  • 15