cDr*_*mer 4 c embedded printf gcc newlib
我正在努力使用 GCC 将 printf 从 newlib 正确实现到我的 esp32 中。
我已经阅读了 newlib 文档,它为我提供了有关如何调用 printf 的一般信息,但没有向我解释后端实现。
根据我当前的研究,我确定 printf 将格式化字符串输出到 STDOUT。在 PC 上,这对我来说更容易理解,因为有一个控制台窗口可以显示 printf 的格式化输出,但是在嵌入式系统上,我知道您必须告诉库将 printf 的格式化输出重定向到哪里,这就是我正在想办法。
再次,根据我的研究,我了解到需要一些功能来完成此任务,特别是功能_write。
我发现如何弥合 printf 和使用该_write函数之间的差距非常困难。我希望这里有人能帮助我理解如何正确实现 printf。
如果我错过了一些清楚解释这一点的文档,那么请将我重定向到该文档。我尝试阅读 newlib 文档以及 GCC 相关文档,但没有真正提到如何使用 printf,但是有大量关于如何调用 printf 和格式化字符串的文档,但这部分很简单。我需要知道如何从 MCU 的 STDOUT 获取格式化字符串。
谢谢大家!
在 Newlib 中,您不实现printf()库中包含的内容。您只需实现一组最小的系统调用即可支持该库。流设备 sycalls API 由open、close和read(write或带有后缀的可重入版本_r)组成 - 如果您使用多线程并且需要每个线程errno(在任何特定于实现的可重入要求中),则此中的可重入性非常有用。
如果您正在实现的只是( 、等stdout使用的流)并且仅支持单个设备(通常是 UART)并且不关心重定向或重入的能力,则、和可以为空,并且可以简单地将提供的缓冲区直接输出到低级串行 I/O API:printf()putchar()puts()openclosereadwrite
int _write(int handle, char *data, int size )
{
int count ;
handle = handle ; // unused
for( count = 0; count < size; count++)
{
outputByte( data[count] ) ; // Your low-level output function here.
}
return count;
}
Run Code Online (Sandbox Code Playgroud)
注意handle这里没有使用。因为stdout它将是 1(stdin= 0 和stderr= 2)。如果您想要单独的输出设备,或者如果您支持其他设备或文件系统和/或重定向,handle则将使用该参数。它用于识别由 开启的蒸汽。通过忽略所有流输出(例如将以相同的方式处理并输出到相同的设备);在许多情况下(其中只是获取调试输出的一种方法,或者您的应用程序没有您不关心的文件系统。stdoutstderrfopenstdoutopenfprintf()printf()
给定该write函数,printf()将“正常工作”(以最简单的方式),因为在幕后所有 stdio 输出函数都调用write)。建议使用缓冲且非阻塞的低电平输出函数(例如中断驱动的UART 驱动程序)。
显然,如果您也想接受输入stdin,您可以实现类似的read功能。
如果你想要一个堆(malloc()等),你还需要实现sbrk/ sbrk_r。如果 Newlib 系统调用中没有其他内容,我建议您至少实现这一点。
Bill Gaitliff在嵌入式系统中的移植和使用 Newlib中讨论了对系统调用实现的更复杂的处理,而此处讨论了基本实现,而Newlib 文档本身提供了与上述类似的示例最小实现存根。