snprintf 无法按预期使用 avr-gcc
snprintf not working as expected with avr-gcc
在调试期间,我发现在使用 avr-gcc 编译代码时 snprintf
没有按预期工作。示例代码应该简单地将浮点值 3999.9f
转换为其字符表示形式。
这是一个最小的测试用例:
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 '[=10=]' 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] != '[=10=]')
{
return -2;
}
return 0;
}
int main(void)
{
int retVal = TestSnprintf();
return 0;
}
使用 avr-gcc 编译此示例代码并使用 Atmel Studio 7 运行 编译此示例代码会得到 return 值 -2。这意味着 snprintf
不工作。
目前我尝试过的:
- 我在 32 位和 64 位 Linux 上测试了代码,它按预期工作(
TestSnprintf
return 值 0)。
- 我用 Visual Studio 2015 测试了代码,它按预期工作(
TestSnprintf
return 值 0)。
buf
的内容是
buf[0] = 32;
buf[1] = 32;
buf[2] = 32;
buf[3] = 32;
buf[4] = 32;
buf[5] = 63;
buf[6] = 0;
使用JTAG接口在设备上进行测试。我也试了模拟器,结果一样。
- 没有激活编译器优化。代码用
-O0
. 编译调试
这是调试会话的屏幕截图,显示 return 值为 -2.
这表明 buf
在调试期间在范围内:
问题
我做错了什么?
解决方案
首先非常感谢大家的帮助!
正如@manilo 所指出的,缺少以下链接器选项:
-Wl,-u,vfprintf -lprintf_flt -lm
printf()
(和朋友们)有三种不同的实现方式。默认不实现float输出。
如果不链接 libprintf_flt.a
(-lprintf_flt
) 和 libm.a
(-lm
),snprintf
将无法工作。
此外,根据文档,您必须添加链接器选项 -Wl,-u,vfprintf
(例如 here)。
链接器标志的顺序很重要:-Wl,-u,vfprintf -lprintf_flt -lm
"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
在调试期间,我发现在使用 avr-gcc 编译代码时 snprintf
没有按预期工作。示例代码应该简单地将浮点值 3999.9f
转换为其字符表示形式。
这是一个最小的测试用例:
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 '[=10=]' 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] != '[=10=]')
{
return -2;
}
return 0;
}
int main(void)
{
int retVal = TestSnprintf();
return 0;
}
使用 avr-gcc 编译此示例代码并使用 Atmel Studio 7 运行 编译此示例代码会得到 return 值 -2。这意味着 snprintf
不工作。
目前我尝试过的:
- 我在 32 位和 64 位 Linux 上测试了代码,它按预期工作(
TestSnprintf
return 值 0)。 - 我用 Visual Studio 2015 测试了代码,它按预期工作(
TestSnprintf
return 值 0)。 buf
的内容是buf[0] = 32; buf[1] = 32; buf[2] = 32; buf[3] = 32; buf[4] = 32; buf[5] = 63; buf[6] = 0;
使用JTAG接口在设备上进行测试。我也试了模拟器,结果一样。
- 没有激活编译器优化。代码用
-O0
. 编译调试
这是调试会话的屏幕截图,显示 return 值为 -2.
这表明 buf
在调试期间在范围内:
问题
我做错了什么?
解决方案
首先非常感谢大家的帮助! 正如@manilo 所指出的,缺少以下链接器选项:
-Wl,-u,vfprintf -lprintf_flt -lm
printf()
(和朋友们)有三种不同的实现方式。默认不实现float输出。
libprintf_flt.a
(-lprintf_flt
) 和 libm.a
(-lm
),snprintf
将无法工作。
此外,根据文档,您必须添加链接器选项 -Wl,-u,vfprintf
(例如 here)。
链接器标志的顺序很重要:-Wl,-u,vfprintf -lprintf_flt -lm
"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