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:
TestSnprintf
return the value 0).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.
-O0
.Here is a screenshot from the debugging session, that demonstrates that the return value is -2.
This demonstrates that buf
is in scope during debugging:
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
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