如何从Newlib在GCC中实现printf?

wfsdck30  于 2023-06-21  发布在  其他
关注(0)|答案(1)|浏览(150)

我正在努力使用GCC将printf从newlib正确地实现到我的esp 32。
我已经看过newlib文档,它给了我关于如何调用printf的一般信息,但没有向我解释后端实现。
根据我目前的研究,我确定printf向STDOUT输出格式化的字符串。在PC机上,这对我来说更容易理解,因为有一个控制台窗口可以显示printf的格式化输出,但是在嵌入式系统上,我理解你必须告诉库将printf的格式化输出重定向到哪里,这就是我试图弄清楚的。
同样,根据我的研究,我已经了解到需要一些函数来实现这一点,特别是函数_write
我发现如何弥合printf和使用_write函数之间差距非常困难。我希望这里有人能帮助我理解如何正确地实现printf。
如果我错过了一些文档,清楚地解释了这一点,那么请重定向我。我试着阅读newlib文档,以及GCC相关文档,但没有真正提到如何使用printf,但有很多关于如何调用printf和格式化字符串的文档,但这部分很容易。我需要知道如何从MCU的STDOUT中获取格式化字符串。
感谢大家!

jhkqcmku

jhkqcmku1#

在Newlib中,您不实现库中包含的printf()。您只需实现一组最小的系统调用来支持库。流设备sycalls 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)。如果您希望为stdoutstderr使用单独的输出设备,或者如果您支持其他设备或文件系统以及fopenstdout重定向,则将使用handle参数。用于识别open打开的蒸汽。通过忽略它所有的流输出(如fprintf()将以相同的方式处理并输出到相同的设备);在许多情况下(其中printf()只是获取调试输出的一种方式,或者您的应用程序没有文件系统),您不会关心。
假设write函数,printf()将“正常工作”(以最简单的方式),因为在引擎盖下,所有的stdio输出函数都调用write)。缓冲和非阻塞的低电平输出功能(例如中断驱动的UART驱动器)。
显然,如果你也想在stdin上接受 input,你应该实现一个类似的read函数。
如果你想要一个堆(malloc()等),你还需要实现sbrk/sbrk_r。我建议您至少在Newlib系统调用中实现它。
Bill Gaitliff在Porting and Using Newlib in Embedded Systems中讨论了系统调用实现的更复杂的处理,而基本实现在here中讨论,而类似于上面的示例最小实现存根在Newlib documentation本身中提供。

相关问题