如何从Newlib在GCC中实现printf? [英] How do you Implement printf in GCC from Newlib?
问题描述
我正在努力使用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由open
,close
,read
和write
(或后缀为_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),并且不关心此功能要重定向或重新进入,则open
,close
和read
可以为空,而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).如果您要为stdout
和stderr
单独使用输出设备,或者如果您正在支持其他设备或文件系统以及fopen
或stdout
重定向,则将使用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屋!