如何从Newlib在GCC中实现printf?

时间:2019-03-06 01:15:09

标签: c gcc embedded printf newlib

我正在努力使用GCC从newlib到我的esp32中正确实现printf。

我已经阅读了newlib文档,它为我提供了有关如何调用printf的一般信息,但没有向我解释后端实现。

根据我目前的研究,我确定printf将格式化的字符串输出到STDOUT。在PC上,这对我来说比较容易理解,因为有一个控制台窗口可以显示printf的格式化输出,但是在嵌入式系统上,我知道您必须告诉库将printf的格式化输出重定向到何处,这就是我想弄清楚。

再次,根据我的研究,我了解到要实现此功能需要一些功能,特别是功能_write

我发现如何弥合printf与利用_write函数之间的差距非常困难。我希望这里的人可以帮助我了解如何正确实现printf。

如果我错过了一些清楚地说明此问题的文档,请重定向到该文档。我尝试阅读newlib文档以及与GCC相关的文档,但是并没有真正提到如何使用printf,但是有很多关于如何调用printf和格式化字符串的文档,但这很简单。我需要知道如何从MCU的STDOUT获取格式化的字符串。

谢谢大家!

1 个答案:

答案 0 :(得分:0)

在Newlib中,您没有实现库中包含的printf()。您只需实现最少的syscall集即可支持该库。流设备sycall API由openclosereadwrite(或后缀为_r的可重入版本)组成-在此重入非常有用如果您正在使用多线程并且需要每个线程errno(在任何实现特定的重新进入要求中)。

如果您仅实现stdoutprintf()putchar()puts()等使用的流)并且仅支持单个设备(通常是UART) )并且不关心重定向或重新进入的能力,那么opencloseread可以为空,而write可以直接将提供的缓冲区直接输出到您的低级串行I / O API:

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;
}

请注意,这里handle尚未使用。对于stdout,它将为1(stdin = 0且stderr = 2)。如果您想为handlestdout使用单独的输出设备,或者如果您正在支持其他设备或文件系统以及stderr或{{1},则使用fopen参数重定向。它用于标识stdout打开的蒸汽。通过忽略它,所有流输出(例如open都将以相同的方式处理并输出到同一设备);在许多情况下(fprintf()只是获取调试输出的一种方法,或者您的应用程序没有不需要的文件系统。

考虑到printf()函数write将“正常工作”(以最简单的方式),因为所有stdio输出函数都在后台调用printf()。建议使用具有缓冲且无阻塞的低级输出功能(例如,中断驱动的UART驱动程序)。

很显然,如果您也想在write上接受 input ,则可以实现类似的stdin函数。

如果您要堆(read等),则还需要实现malloc() / sbrk。我建议您至少在Newlib syscalls中没有其他实现。

Bill Gaitliff在Porting and Using Newlib in Embedded Systems中讨论了对系统调用实现的更复杂处理,而在here中讨论了基本实现,而{{3}中提供了与上面类似的示例性最小实现存根。 }本身。