STM32搭载RT-Thread系统时的rt_sprintf函数和stdio.h的sprintf函数的区别
1.问题来源
在工作中,使用STM32搭载RT-Thread操作系统,使用的字符串打印函数一般使用操作系统带的rt_sprintf函数,在使用过程中,将一个浮点数和字符串打印到字符型的数组中时,这个运行的线程就崩了,经过同事解说,了解到rt_sprintf和sprintf有区别,rt_sprintf函数更换成了sprintf后,问题立刻解决,在度娘搜索后没有看到这个问题的说明,在此深入探究两个函数的区别
2.问题探究
(1).stdio.h中的sprintf函数
函数代码
#pragma __printf_args
extern _ARMABI int sprintf(char * __restrict /*s*/, const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1,2)));
/*
* is equivalent to fprintf, except that the argument s specifies an array
* into which the generated output is to be written, rather than to a
* stream. A null character is written at the end of the characters written;
* it is not counted as part of the returned sum.
* Returns: the number of characters written to the array, not counting the
* terminating null character.
*/
#pragma __printf_args
extern _ARMABI int _sprintf(char * __restrict /*s*/, const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1,2)));
/*
* is equivalent to sprintf, but does not support floating-point formats.
* You can use instead of sprintf to improve code size.
* Returns: as sprintf.
*/
(2).RT_Thread操作系统中的rt_sprintf函数
函数代码
/**
* This function will fill a formatted string to buffer
*
* @param buf the buffer to save formatted string.
*
* @param format is the format parameters.
*
* @return The number of characters actually written to buffer.
*/
int rt_sprintf(char *buf, const char *format, ...)
{
rt_int32_t n;
va_list arg_ptr;
va_start(arg_ptr, format);
n = rt_vsprintf(buf, format, arg_ptr);
va_end(arg_ptr);
return n;
}
RTM_EXPORT(rt_sprintf);
(3).问题解决说明
后面看了源码才知道是rt_sprintf无法打印浮点数,具体的现象可以看一下这个,
https://blog.csdn.net/plokm789456/article/details/107087502/
解决方法1
将搭载RT-Thread操作系统的工程中要使用到的“打印”相关函数更换成C语言库stdio.h的函数,例如:rt_sprintf更换成sprintf,在工程文件中添加stdio.h头文件。这是在上层应用程序中解决问题。
解决方法2
将搭载RT-Thread操作系统工程的“打印”函数源码n = rt_vsprintf(buf, format, arg_ptr)
中的rt_
删了就可以了。例如:将rt_sprintf函数中的rt_
删了,
/**
* This function will fill a formatted string to buffer
*
* @param buf the buffer to save formatted string.
*
* @param format is the format parameters.
*
* @return The number of characters actually written to buffer.
*/
int rt_sprintf(char *buf, const char *format, ...)
{
rt_int32_t n;
va_list arg_ptr;
va_start(arg_ptr, format);
n = vsprintf(buf, format, arg_ptr);
va_end(arg_ptr);
return n;
}
RTM_EXPORT(rt_sprintf);
这样源码中的关键函数使用的是C语言库stdio的函数,就没什么问题了。
(4).举一反三
/**
* This function will print a formatted string on system console.
*
* @param fmt is the format parameters.
*
* @return The number of characters actually written to buffer.
*/
RT_WEAK int rt_kprintf(const char *fmt, ...)
{
va_list args;
rt_size_t length;
static char rt_log_buf[RT_CONSOLEBUF_SIZE];
va_start(args, fmt);
/* the return value of vsnprintf is the number of bytes that would be
* written to buffer had if the size of the buffer been sufficiently
* large excluding the terminating null byte. If the output string
* would be larger than the rt_log_buf, we have to adjust the output
* length. */
length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
if (length > RT_CONSOLEBUF_SIZE - 1)
length = RT_CONSOLEBUF_SIZE - 1;
#ifdef RT_USING_DEVICE
if (_console_device == RT_NULL)
{
rt_hw_console_output(rt_log_buf);
}
else
{
rt_device_write(_console_device, 0, rt_log_buf, length);
}
#else
rt_hw_console_output(rt_log_buf);
#endif /* RT_USING_DEVICE */
va_end(args);
return length;
}
RTM_EXPORT(rt_kprintf);
#endif /* RT_USING_CONSOLE */
这是RT_Thread操作系统中的rt_kprintf
函数的源码,rt_kprintf
函数的作用是将串口重映射到rt_kprintf
,通过rt_kprintf
打印信息,但是在代码操作过程中无法打印出浮点数。
打印现象如下
%f
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Jul 8 2022 09:56:08
2006 - 2021 Copyright by rt-thread team
将源码中的rt_删了之后重新打印现象如下
0.200000
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Jul 8 2022 10:00:11
2006 - 2021 Copyright by rt-thread team