-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Add function "printf" to AVR core class "print" #5938
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This "printf" realization not use "sprintf" and buffers in RAM. If it is not used, the compiler does not add any extra code. Exelent for AVR.
If this idea is promising, then I can write variants for ARM,ESP8266.
trlafleur
commented
Mar 25, 2017
yes we need this. this is long over due....
Don't you need to pull the fmt
string from program memory in the const __FlashStringHelper *
version before passing it to vfprintf
, as that one does not know about PGMSPACE?
Also, it's worth pointing out that this won't work with Arduino's String
, although I'm not sure people use this anyway. (I did some experiments back in the day with my own implementation of Print::printf, which used vsnprintf
instead of vfprintf
, which people on the mailing list didn't seem to like; your approach is probably the way to go.)
Other than that, I think this would be a useful addition. I have already proposed a variadic Serial.print()
(PR #5829) which allows printing several arguments at once, but this would also add C-style formatting.
Don't you need to pull the fmt string from program memory... ?
It not need.
AVR libc vprintf has a flag indicating that the format string is in FLASH, and works with it directly from flash.
It is only necessary to set it correctly.
..this won't work with Arduino's String..
This will work with the String type, as usual, the s.c_str().
The standard printf takes a type char*..
Theoretically, it is possible to make the printf accept an argument of the "String" type.
I do not know who needs it, but it's a platform for experiments.
But, it's better not to do it, because it's not standard.
..printing several arguments at once..
Classic printf is more standard, and consumes less RAM, which is small.
Moreover, it is all the same as outputting to the serial port, and on the LSD, TFT display and files the formatted output is almost always needed.
For this there are two 3 ways:
- sprint(). Cross-platform, but large consumption of RAM (the problem is only on the AVR)
- Streams. Under each platform differently. fdevopen(avr), fopencookie() (gcc arm, linux) ... (on esp8266 problem)
- Serial.printf(), TFT.printf(), File.printf() - simply, cross-wise within Arduino. (Tested on AVR/STM32/ESP8266/OrangePI)
Where is the conflict?
Maybe I did not notice something.
Added self-contained functions.
If the "printf" is not used, then they and "libs" are not linked.
Projects that do not use "printf" do not consume memory.
Also i see also added "flush()". It's good.
It is not needed on the AVR libc, but it's necessary on the ARM libc.
And the source code must be portable.
Ps: I and my friends use "printf" for a year, and we add it every time we update Arduino, and I did not notice any problems.
- AVR libc vprintf has a flag
My bad; I was not aware of that __SPGM
flag. (There's also a vfprintf_P()
function btw, but I guess pulling a single function from the library is better than pulling 2.)
s.c_str()
My point was that this is not obvious so I was emphasizing that it would need to be clearly stated in the documentation. (Also it is not as newbie-friendly as passing it directly.)
Theoretically, it is possible to make the printf accept an argument of the "String" type.
Not directly at least. String
happens to be a non-trivially copyable type (because it has a non-trivial copy constructor String(const String &)
, so attempting to pass that to a C-style variadic function gives you an error.
This could be solved with some variadic template magic (which would replace any String
with its .c_str()
so you wouldn't need to implement your own String
formatter), but that seems like an overkill as the solution is to just append .c_str()
as you mentioned.
- Classic printf is more standard, and consumes less RAM, which is small.
Which reminds me, AVR's printf
does not implement floating point formatting by default; if you use %f
et al you get a ?
instead. Floating point support needs to be added explicitly when compiling avr-libc, with the extra resource usage this implies.
Also, apparently *
is not supported, so variable precision/digits won't work either.
(Regarding size, I want to clarify that #5829 heavily relies on inlining so it won't use more memory than multiple calls to Serial.print
, but then again I don't know how memory-efficient that is compared to printf
.)
the formatted output is almost always needed.
I think we can all agree that, when it comes to efficient formatting, nothing beats printf
. This is why I think this would be a valuable addition to Arduino. (There was some discussion on adding more formatting to Print::print
but the proposals were rather complex.)
Additionally, adding printf
and encouraging its use would have educational value for people who are using Arduino to learn C.
However, I think #5829 is more convenient for the average user, but there's no reason to not merge both.
Flush() - for libc.stream it is necessary to remove, and we do not use it.
Buffering for the print () stream is not needed.
The Print class already has buffering for output.
(Moreover, buffering n libc.FILE is not for speedup, but for multithreaded code)
ideaalab
commented
Mar 22, 2019
Is this going somewhere?
I would really like to see printf in Arduino....
Im writing a lot of text in TFT and im going nuts!
Is this going somewhere?
No, it is not going anywhere, and you should not expect it ever go anywhere. Massimo Banzi said very clearly on the Arduino developers mail list that Arduino does not believe the printf syntax belongs in the official Arduino API.
ideaalab
commented
Mar 25, 2019
Massimo Banzi said very clearly [...] that Arduino does not believe the printf syntax belongs in the official Arduino API.
Thats a pity... And i can not understand why. It just adds functionality, that you can use or not... If you dont use it, then it should not even enlarge the compiled file.
And ok... lets say he dont want to be part of the core... why not implement as a library, like with eeprom, spi, i2c... All those comes with arduino. Why not also a printf?
Simple print is ok for newbies and hobbyist... but its not elegant or professional to write in 10 lines of what it could be programmed in just single line with printf...
No, it is not going anywhere, and you should not expect it ever go anywhere. Massimo Banzi said very clearly on the Arduino developers mail list that Arduino does not believe the printf syntax belongs in the official Arduino API.
This is a pity and makes little sense. I understand that Arduino aims for simplicity and that printf has a somewhat complex syntax, but I imagine many Arduino programmers may come from C and be used to printf syntax, so why not leave that as an option as well? Even if Arduino promotes the default Serial.print as the preferred one, it'd be nice to have Serial.printf as well, especially for C programmers. It gives a lot of flexibility and @u48's implementation seems very elegant.
Alternatively, a syntax like Python's str.format() would be nice and simple enough, but that seems hard to implement.
Simple print is ok for newbies and hobbyist... but its not elegant or professional to write in 10 lines of what it could be programmed in just single line with printf...
Another alternative addressing that would be something like what I proposed in #5829 (IMO very clean and simple too), where you can just put multiple arguments to Serial.print() and they get concatenated, but that doesn't seem to be going anywhere either.
Are you really, honestly & genuinely asking this question?
so why not leave that as an option as well?
Or is is merely rhetorical, where no answer will be considered as a valid reason? (what I've seen from absolutely everyone else who's talked as you do now)
It was mostly rhetorical indeed (let's say about 70%), but more as a prompt for constructive debate and trying to make a point rather than an "I'm right and you'll never convince me otherwise" statement. I would also like to understand the possible arguments why adding Print.printf may be a bad idea (if the only reason is "the syntax is ugly and hard to document, and doesn't quite fit with the rest of the Arduino syntax" (which is an acceptable argument, don't get me wrong), I personally think the advantages may outweight the disadvantages).
Re: Massimo Banzi having said very clearly that "Arduino does not believe the printf syntax belongs in the official Arduino API"; all he said (if I found the right mail) is that he would personally avoid it, but it didn't seem like a resounding "no" to me. (He also points out that sprintf can be used as an alternative if you really want to use printf syntax, but I think that's a bit complicated for people who just know enough C to use printf.)
Maybe we should take this discussion to the mailing list instead?
Related: arduino/ArduinoCore-API#28
If we'll ever decide that we cannot live without a printf
implementation it should be added in a cross-platform way in https://github.com/arduino/ArduinoCore-API , so I'm closing this one. For all the further development of this functionality please refer to arduino/ArduinoCore-API#28
Add to AVR core class "print":
size_t printf (const char *szFormat, ...);
size_t printf (const __FlashStringHelper *szFormat, ...);
This is does not use the "sprintf" and buffers in RAM.
If it is not used, the compiler does not add any extra code.
For AVR Excellent.
You can write more readable code:
Serial.printf (F ("Var = 5%"), Var);
Serial.printf ("Var = 5%", Var);
LCD.printf (F ("Var2 = 3% Var3=0x%04X"), Var2, VAR2);
On large projects, the overall code size is significantly reduced when using printf.
Note:
For ARM this is code not working.
For ARM need to use GNU extension "fopencookie" or a "retarget putsch" way.