WizenedEE

When people either get fed up with using a series of Serial.print()s or want to do things the Print library cannot (like constant width numbers), common advice on the forums is to use sprintf to print to a buffer and then use Serial.print(buf). However, there are several things wrong with that. The first is that it's kind of annoying -- it takes at least three lines to just print out one line. The second, and more important problem, is that you need to anticipate the largest size print you'll need (easily possible, but again annoying) and have that much free RAM (which may be impossible). However, there is a way around it -- by using printf directly and having it print one character at a time to the Serial stream.

This page: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html is where I found most of the information needed to do this. It isn't too hard to set this up for your own sketch:

However, I then thought about making this so that it would be easier to use. I tried two things: the first was modifying wiring.c to add the setting up to the init() function. This ended up working (although I had to compile wiring.c as a c++ file: the result is here), and I think it's not unreasonable to suggest that this change is incorporated into the main IDE (thoughts?) However, I then thought about making it into a library, and with a little trickery I managed to get it to work (although I think there's more overhead than necessary). The link to the library is here: https://github.com/WizenedEE/arduino/tree/master/libraries/stdinout and here's a sketch where I use both printf and scanf heavily (it controls a robot with a PID loop): https://github.com/WizenedEE/arduino/blob/master/rover5/PIDTest/PIDTest.ino

When using the library, remember that the %f flag doesn't work unless you add some linker options, described on the nongnu page.

Any suggestions on how to call the setup_stdin_stdout() without user interaction would be nice. The method I use is described in Thinking in C++ volume 1, chapter 10. I also tried putting the function in the .init section, but it didn't appear to work (stdin and stdout were not set up)

I tried making a class with the constructor calling the function and then making an instance local to the .cpp file, but that didn't appear to call it either (and it's hard to debug because Serial isn't setup until the setup() function is called)

Both are a lot more modern and user friendly (AND SAFER) than sprintf. Variadic templates are the most intuitive IMO, but are only available with C++11 which the AVR compiler doesn't support. g++-arm-none, on the other hand, is actually not junk and does C++14 . AFAIK all methods will require a small buffer when putting ints and floats to a stream.

The manipulators build up a proxy object which is used to store the formatting features. Due to the manipulators being types, they are all compile time constants. The stream functionality is optimized simply to xx.print(...) calls.

I have had a peek at your StaticString lib and it is something I was thinking of replicating a while ago. However PrintEx contains a string which can be printed or streamed to (different take on a string).

That's interesting, your GString is similar in function to my Rope class only Rope doesn't have manipulators like GString. It's a pretty good way to handle strings IMO. Does GString know where the end of the buffer is? My biggest gripe against C string functions is that they will happily chew up memory they shouldn't.

No, it'll happily overrun the buffer. Its entirely up to the user to ensure they provide the correct amount of storage.

I've thought about a 'safe' version however I haven't seen really any circumstances where code can't be factored to appropriately provide initial storage (embedded systems anyway). I thought of adding debug error handling which would provide errors on overrun allowing a user to change their buffers. Then use the more efficient method in release (no error checking).

Yeah, I guess it's generally not too hard to make buffers big enough. It's mostly things like sprintf(buf, "%s", a_string_of_unknown_length_that_possibly_isnt_null_terminated); that get you - and there's a lot of that posted on these forums.

I'll look over your code over the next couple of days, hopefully I'll learn more about manipulators.