snprintf not working as expected with avr-gcc
Asked Answered
J

2

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
Johanna answered 14/6, 2016 at 15:6 Comment(21)
And the C standard library is not part of gcc! Which library do you use?Cleareyed
You should find out what buf actually contains.Sulamith
Did you link with libm ? (-lm)Cetology
Why the downvote ? The question is well formatted, easy to understand, offending code is included, OP stated what he has tried..Sulamith
Is <stdio.h> included beforehand?Pitiless
@chux yes it's includedJohanna
How do you check the content of buf?Nevermore
According to this: nongnu.org/avr-libc/user-manual/… you need -lm did you link it in?Cetology
@Cetology Wouldn't it just fail to link id he didn't?Nevermore
@EugeneSh. By running the debugging the code via JTAG directly on the device. I also tried running in the simulator, same result. I tried changing the device, with the same result.Johanna
@Cetology Yes i link with libmJohanna
@Johanna Are you sure you are breaking in the right place? Do you have any other variable named buf around? Can you show the full code?Nevermore
BTW, it can be very well optimized away, as your test code is doing nothing...Nevermore
@EugeneSh. Good point, i added a screenshot that demonstrated that the break point is placed correctly. But Olaf told me is should'nt add them. I'll re-add it.Johanna
Are you sure the printf family is implemented? In general on such small targets like AVR, using these heavyweights is not a good idea. Better write custom functions for simple conversions and use them.Cleareyed
@Johanna Well, Olaf meant that the code should not come in pictures. But if there is some extra info that can be shown by picture only - it should be OK..Nevermore
@orbitcowboy: I did not tell to remove information. Just there is no need to haver the screenshot! Use text!Cleareyed
@Johanna In the place you are showing buf is out of scope.Nevermore
@EugeneSh.: There should be no problem showing the breakpoint in a comment.Cleareyed
@EugeneSh. I will add another screenshot with the break point at return -2, that demonstrates buf is not out of scope.Johanna
I think the answers below are making sense..Nevermore
O
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

Oneway answered 14/6, 2016 at 15:32 Comment(0)
P
0

"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

Pintsize answered 14/6, 2016 at 15:34 Comment(1)
I am using Atmel Studio not an Arduino IDE.Johanna

© 2022 - 2024 — McMap. All rights reserved.