如何从Newlib在GCC中实现printf? [英] How do you Implement printf in GCC from Newlib?

查看:569
本文介绍了如何从Newlib在GCC中实现printf?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm struggling to properly implement printf from newlib into my esp32, using GCC.

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

I've gone through the newlib documentation and it gives me general information about how printf is called, but doesn't explain the back end implementation to me.

根据我目前的研究,我确定printf将格式化的字符串输出到STDOUT.在PC上,这对我来说比较容易理解,因为有一个控制台窗口可以显示来自printf的格式化输出,但是在嵌入式系统上,我知道您必须告诉库将printf的格式化输出重定向到哪里,这就是事实.我正在尝试找出答案.

Based on my current research I have determined that printf outputs a formatted string to the STDOUT. On a PC this was simpler for me to understand because there's a console window that would display the formatted output from printf, however on an embedded system I understand that you have to tell the library where to redirect the formatted output of printf to and that's what I'm trying to figure out.

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

Again, based off of my research I have come to understand that some functions are required to accomplish this, specifically the function _write.

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

I'm finding it very difficult on how to bridge the gap between printf and utilizing the _write function. I'm hoping someone here can help me understand how to properly implement printf.

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

And if I missed some documentation that clearly explains this, then please redirect me to that. I tried reading the newlib documentation, as well as GCC related documentation, but nothing really mentions how to use printf, but there is plenty of documentation on how to call printf and format the string, but that part is easy. I need to know how to get the formatted string from the STDOUT of the MCU.

谢谢大家!

推荐答案

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

In Newlib you don't implement printf() that is included in the library. You simply implement a minimal set of syscalls to support the library. The stream device sycalls API comprises of open, close, read and write (or reentrant versions with the _r suffix) - the reentrancy in this is useful if you are using multi-threading and need a per thread errno (amongst any implementation specific re-entrancy requirements).

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

If all you are implementing is stdout (the stream used by printf(), putchar(), puts() etc.) and are only supporting a single device (typically a UART) and are not concerned about the ability to redirect or reentrancy, then open, close and read can be empty, and write can simply output the provided buffer directly to your low-level serial 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()只是获取调试输出的一种方法,或者您的应用程序没有不需要的文件系统.

Note that handle here is unused. For stdout it will be 1 (stdin = 0 and stderr = 2). The handle argument would be used if you wanted separate output devices for stdout and stderr or if you were supporting additional devices or a file system and fopen or stdout redirection. It is used to identify a steam opened by open. By ignoring it all stream output (such as fprintf() will be handled in the same way and output to the same device); in many cases (where printf() is just a means of getting debug output, or your application has no filesystem you won't care.

鉴于write函数,printf()将正常工作"(以最简单的方式),因为在幕后,所有stdio输出函数均调用write).建议使用具有缓冲且无阻塞的低级输出功能(例如,中断驱动的UART驱动程序).

Given that write function, printf() will "just work" (in the simplest possible manner) because under the hood all stdio output functions call write). A low-level output function that is buffered and non-blocking (e.g. an interrupt driven UART driver) is advised.

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

Obviously if you want to accept input on stdin too, you would implement a similar read function.

如果要堆(malloc()等),则还需要实现sbrk/sbrk_r.我建议您至少在Newlib syscalls中实现该功能.

If you want a heap (malloc() etc) you will also need to implement sbrk / sbrk_r. I would suggest that you at least implement that if nothing else in Newlib syscalls.

Bill Gaitliff在 rel ="nofollow noreferrer"> Newlib文档本身.

A more sophisticated treatment for syscalls implementation is discussed by Bill Gaitliff in Porting and Using Newlib in Embedded Systems, while basic implementation is discussed at here while example minimal implementation stubs similar to that above are provided in the Newlib documentation itself.

这篇关于如何从Newlib在GCC中实现printf?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆