Closed scottchiefbaker closed 4 years ago
Hello Scott,
Thanks for writing in and sending a size comparison. This library is merely a wrapper around mpaland/printf, so the sizing is determined by that library's implementation.
I notice a few things in my testing and reading:
PRINTF_DISABLE_SUPPORT_EXPONENTIAL
saves 1764 bytes in my test case.PRINTF_DISABLE_SUPPORT_LONG_LONG
saves 1266 bytes in my test casePRINTF_DISABLE_SUPPORT_FLOAT
saves a whopping 4,044 byes. Disabling all three of the above options saves 5220 bytes.The PrintEx library is a custom wrapper around the Print
class, while mpaland/printf is written to the C standard. From PrintEx:
The printf implementation found in this library is unique. It has been built directly on top of the Arduino Print library rather than as a separate code base simply called from within. All the features found in printf use a feature already implemented in Print.
It could very well be that there are differences in the two implementations accounting for the remaining size difference, such as additional format flags implemented in mpaland/printf that aren't used in PrintEx.
It could also be that the optimizer is better able to work with the PrintEx inheritance structure. This printf
library is standalone and is only tied to the Print
class through the default implementation of _putchar
.
I'll also add this information to the README, seems useful to note in general.
Thank you for the the very detailed write up. This was by no means meant to disparage this library, I'm just trying to find a good replacement for PrintEx. I love the idea that this has no dependencies and is super simple. On an MCU that's pretty important.
I think the options you mentioned above sound promising. I definitely need floating point support as that was the main reason I need a printf()
implementation. The other two are certainly less common. I'm not sure how I disable them though. If I include
#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL
The output size of my sketch doesn't change. Am I missing something here?
Just for posterity here are my initial findings. Using vanilla options for both libraries on my PrintfTest.ino I get:
Type | Bytes |
---|---|
No Serial | 1606 |
PrintEx | 5056 |
arduino-printf | 9476 |
No disparagement perceived! It's a reasonable question worth exploring.
Due to the design of the mpaland/printf library, these definitions must come from the compiler, rather than defining that before the header. I'll work with the library author on that, as it would be convenient to define them before including the header to control behavior.
If you're using a Makefile or other build system, you'd use the -D
flag (e.g., -D PRINTF_DISABLE_SUPPORT_EXPONENTIAL) to add the necessary variables/commands.
For Arduino IDE, the flags need to be added to the compiler.extra_flags
property in platform.txt
or platform.local.txt
. You would need to restart the IDE for the changes to take effect.
I believe that you can also use the Arduino CLI to control preferences. Some notes: https://forum.arduino.cc/index.php?topic=537500.0
(Will also update the README with better notes on this)
If I disable long long support, and exponential I get:
Type | Bytes |
---|---|
No Serial | 1606 |
PrintEx | 5056 |
arduino-printf | 6328 |
Which is a lot more reasonable. It would be great if you could disable these at compile time with a #define
instead of having to use -D
which is a pain.
Or perhaps better yet, they could default to disabled on an AVR based MCUs, and enabled on bigger more capable boards? I feel like the use case for needing 64 bit ints, and exponents on AVR boards is going to be pretty minimal.
My compile command was:
arduino --verify --pref build.extra_flags="-DPRINTF_DISABLE_SUPPORT_EXPONENTIAL -DPRINTF_DISABLE_SUPPORT_LONG_LONG" --pref build.path=/tmp/arduino-build-PrintfTest/ --port /dev/ttyUSB0 --board arduino:avr:uno /home/bakers/Arduino/PrintfTest/PrintfTest.ino
That's a reasonable request. I'll modify the library source here and work on improvements with the primary project separately.
Sounds good. I look forward to testing it.
I just found out (accidentally) that the ESP8266 and ESP32 Arduino implementations both implement printf()
/sprintf()
natively now. I'm not sure how well documented/publicized that is.
From my testing the ESP implementation of printf()
supports: floating point, long longs, but not exponents.
It might be worth putting in your README.md. If you think it's worthy of mention I can submit a pull request for it.
Definitely worth a note - happy to accept PRs.
Do you know what header ESPxxx defines printf in? I'd like to take a look at what they're doing in the context of another library (arduino-logger)
@phillipjohnston I'm not a C++ expert, it's hard to tell where it gets defined. I think it's here:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/Print.h#L78
Digging a little deeper I think it's here actually:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/Print.cpp#L58
I use PrintEx in a lot of my projects, but it's not maintained any more (last update was 2016). Researching your
printf()
implementation looks promising but it uses a significant amount of storage.Any idea why this implementation is so much larger?
PrintEx
arduino-printf