Skip to content
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

Add function "printf" to AVR core class "print" #5938

Closed
wants to merge 2 commits into from
Closed

Conversation

u48
Copy link

@u48 u48 commented Feb 1, 2017

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.

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.
@mastrolinux mastrolinux added the in progress Work on this item is in progress label Feb 1, 2017
@facchinm facchinm added the Print and Stream class The Arduino core library's Print and Stream classes label Feb 9, 2017
@u48
Copy link
Author

u48 commented Feb 13, 2017

If this idea is promising, then I can write variants for ARM,ESP8266.

@trlafleur
Copy link

yes we need this. this is long over due....

@cousteaulecommandant
Copy link
Contributor

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.

@u48
Copy link
Author

u48 commented May 18, 2017

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:

  1. sprint(). Cross-platform, but large consumption of RAM (the problem is only on the AVR)
  2. Streams. Under each platform differently. fdevopen(avr), fopencookie() (gcc arm, linux) ... (on esp8266 problem)
  3. Serial.printf(), TFT.printf(), File.printf() - simply, cross-wise within Arduino. (Tested on AVR/STM32/ESP8266/OrangePI)

@u48
Copy link
Author

u48 commented May 25, 2017

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.

@cousteaulecommandant
Copy link
Contributor

@u48 The conflict is due to ed7007c which was merged 2 days ago (although the original commit is from 2014).
Nothing serious; they just added a method to Print; it's just that it happens to be at the end where you added your printf.

@cousteaulecommandant
Copy link
Contributor

  1. 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.)

  1. 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.

  1. 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.

@u48
Copy link
Author

u48 commented May 30, 2017

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
Copy link

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!

@PaulStoffregen
Copy link
Contributor

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
Copy link

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...

@cousteaulecommandant
Copy link
Contributor

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.

@PaulStoffregen
Copy link
Contributor

PaulStoffregen commented Jun 3, 2019

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)

@cousteaulecommandant
Copy link
Contributor

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?

@per1234
Copy link
Collaborator

per1234 commented Jun 16, 2019

Related: arduino/ArduinoCore-API#28

@facchinm
Copy link
Member

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

@facchinm facchinm closed this Sep 20, 2019
@per1234 per1234 added Type: Invalid Off topic for this repository, or a bug report determined to not actually represent a bug and removed in progress Work on this item is in progress labels May 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Print and Stream class The Arduino core library's Print and Stream classes Type: Invalid Off topic for this repository, or a bug report determined to not actually represent a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants