我正在运行带有ARM Cortex-M3(STM32F205)的裸机嵌入式系统。 当我尝试使用带浮点数的snprintf()
时,例如:
float f; f = 1.23; snprintf(s, 20, "%5.2f", f);
我把垃圾变成了垃圾。 格式似乎很荣幸,即垃圾是一个格式良好的字符串,包含数字,小数点和两个尾随数字。 但是,如果我重复snprintf
,字符串可能会在两次调用之间发生变化。
浮点数学似乎在其他方面起作用,而snprintf
与整数一起工作,例如:
snprintf(s, 20, "%10d", 1234567);
我将newlib-nano
实现与-u _printf_float
链接器开关一起使用。 编译器是arm-none-eabi-gcc
。
我确实怀疑内存分配问题,因为整数打印没有任何打嗝,但浮动表现就好像它们在过程中被破坏一样。 printf
系列函数使用浮点数调用malloc
,而不是整数。
我在这个上下文中使用的唯一不属于newlib
的代码是我的_sbrk()
,它是malloc
所必需的。
caddr_t _sbrk(int incr) { extern char _Heap_Begin; // Defined by the linker. extern char _Heap_Limit; // Defined by the linker. static char* current_heap_end; char* current_block_address; // first allocation if (current_heap_end == 0) current_heap_end = &_Heap_Begin; current_block_address = current_heap_end; // increment and align to 4-octet border incr = (incr + 3) & (~3); current_heap_end += incr; // Overflow? if (current_heap_end > &_Heap_Limit) { errno = ENOMEM; current_heap_end = current_block_address; return (caddr_t) - 1; } return (caddr_t)current_block_address; }
据我所知,这应该有效。 似乎没有人用负增量来调用它,但我想这是由于newlib malloc
的设计。 唯一有点奇怪的是,对_sbrk
的第一次调用有一个零增量。 (但这可能只是malloc
对堆的起始地址的好奇心。)
堆栈不应该与堆冲突,因为这两个堆栈大约有60 KiB RAM。 链接器脚本可能是疯了,但至少堆和堆栈地址似乎是正确的。
由于可能发生其他人被同一个bug咬了,我会回答我自己的问题。 然而,正是@Notlikethat的评论提出了正确答案。
这是你不应该偷的教训。 我借用了STMCubeMX代码生成器附带的gcc链接器脚本。 不幸的是,脚本和启动文件都被破坏了。
原始链接描述文件的相关部分:
_estack = 0x2000ffff;
和它在启动脚本中的对应物:
Reset_Handler: ldr sp, =_estack /* set stack pointer */ ... g_pfnVectors: .word _estack .word Reset_Handler ...
第一个中断向量位置(在0处)应始终指向启动堆栈顶部。 当达到复位中断时,它也会加载堆栈指针。 (据我所知,后者是不必要的,因为硬件无论如何都会在调用重置处理程序之前从第0个向量重新加载SP。)
Cortex-M堆栈指针应始终指向堆栈中的最后一项。 在启动时,堆栈中没有项目,因此指针应指向实际内存上方的第一个地址,在这种情况下为0x020010000。 使用原始链接描述文件,堆栈指针设置为0x0200ffff,这实际上导致sp = 0x0200fffc(硬件强制字对齐堆栈)。 在此之后,堆栈未对准4。
我通过删除_estack
的常量定义并将其替换为_estack
更改链接器脚本,如下所示。 以前有内存定义。 我更改了名称只是为了查看值的使用位置。
MEMORY { FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } _stacktop = ORIGIN(RAM) + LENGTH(RAM);
在此之后_stacktop
的值是0x20010000,并且我的数字浮动得很漂亮……任何使用双长度参数的外部(库)函数都会出现同样的问题,因为ARM Cortex ABI声明堆栈必须对齐到8个八位字节时调用外部函数。
snprintf接受size作为第二个参数。 您可能想要通过此示例https://www.cplusplus.com/reference/cstdio/snprintf/
/* snprintf example */ #include int main () { char buffer [100]; int cx; cx = snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 ); snprintf ( buffer+cx, 100-cx, ", and the half of that is %d.", 60/2/2 ); puts (buffer); return 0; }
以上就是c/c++开发分享snprintf()使用newlib nano打印垃圾浮动相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/562315.html