basic_usage.ino and %n format specifier
There appears to be some issues with the basic_usage.ino example. It is attempting to use %n with sprintf() and %n has a different meaning. The compiler issues warnings and the code does not appear to generate the desired result.
This brings up a more general question of the 'n' format specifier as it appears that PrintEx has hijacked that specifier to mean something else.
While it would totally break backward compatibility, perhaps a different specifier character could be used? Like maybe 'N' or 'r' instead as those do not seem to be use by the standard xxprintf() functions.
I'll implement it as %r maybe. Although the EEPROM will need a new specifier.
It'll be a breaking change, so I'll have to do a big check to see if there is anything else that needs changing to before moving to 2.0.0.
I'm considering adding the actual specifier %n to do what it is supposed to do.
I've also overlooked the %p specifier, I might as well implement that too. This will force the repeat, and PROGMEM specifiers to change.
I overlooked the %r as already being used. It is really tough to find something that isn't already in use.
Oddly enough in some testing I just did for this on the pic32 core, %n on that platform is a decimal integer similar to %d. That is not what it does on AVR or what the documents I've read specify for %n I don't know what the answer is anymore. Maybe %n is ok as it is???
I guess perhaps it may be time to go look at POSIX & latest C standard and see what format characters are in use.
I have been using this as my guide to what the correct options are: http://www.cplusplus.com/reference/cstdio/printf/
These format strings get pretty sticky.
Here are the formats from POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
POSIX seems to only require a subset of all the POSIX defined formats. (see first link above)
modifiers:
#
0
-
<SPACE>
+
,
I (capital letter i, linux glibc 2.2 extension)
conversions:
a
A
b (see POSIX printf() link above)
c
C
d
e
E
f
F
g
G
hh
h
i
j
l
ll
L
m
n
o
p
s
S
t
u
x
X
z
%
%p is used to print out a pointer PrintEx is using it for progmem (flash) strings so that is a collision as well as the %n repeat.
Seems like really tough choices to keep compatible with existing POSIX and AVR libc formats. Here are some options that unfortunately are not compatible with existing PrintEx format strings.
%P for Progmem? %D for epprom Data? %r or %R for Repeat operation?
I would think that %R might be preferred over %r as %r was used in some really ancient formatting code before varargs was implemented just to pick a character that has no known previous usage.
I think it'd be simplest to stick with the C standard library. The link I posted is seems to be the ones required for a standard C implementation. This will mean I'll have to change both %n and %p.
I'd use %r for repeat.
I have a proposal for this ready in the branch 'printf_specifiers'.
Adding the new features only adds on 86 bytes.
All new features work:
signed int count, total;
total = serial.printf( "\n\n%20r\nFloat: %07.3f\nPROGMEM: %t\nPointer: %p%n\n%20r\n\n", '=', 35.85f, F("A PGM String"), (void*) 0xABCD, &count, '=' );
Serial.println( count );
Serial.println( total );
The format specifiers used by ANSI, LInux, POSIX and the cpp referenced you pointed to are nearly all identical. I was only trying to be helpful by listing all the existing specifiers across all of them to aid in picking new ones that are not or have not been used. And offered a suggestion that I thought seemed to be helpful by using characters based on using a letter that involved a mnemonic character for the type name. but obviously the choice is up you.
But I will say that I don't think using %t is a good choice for Arduino F() and progmem strings. t is already used as length modifier for other specifiers similar to l or h or z etc... There is a table of them on the cpp reference page: http://www.cplusplus.com/reference/cstdio/printf/
I'd recommend using a character for the F() (progmem on AVR) string specifier that is not already being used for something else. Actually I just went back an looked closely at the AVR stdio documentation. http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1 AVR libC actually already uses %S for progmem memory strings conversion specifier. So %S would probably be the optimal choice even though %S has special meaning in POSIX to mean %lc which means a pointer to wchar_t characters, but those types of chars are not really used in these environments.
Yeah, the AVR memory architecture really sucks..... None of the other processors have to deal with this. So much code has to be wonked up to support const data on the AVR.
From a compatibility stand point, I'm assuming that %S (or whatever the final format char is) will work on all platforms not just AVR.
So application code can do something like this:
sprintf(buf, F("flash string: %S"), F("FLASH"));
and it works on all platforms.
The format specifiers used by ANSI, LInux, POSIX and the cpp referenced you pointed to are nearly all identical. I was only trying to be helpful by listing all the existing specifiers across all of them to aid in picking new ones that are not or have not been used.
Was quite helpful, thanks. I just didn't scroll down far enough to see the t was already in use.
Using 'S' is a good idea. Then both RAM and Flash strings use s/S.
I have a PR ready with the changes we discussed.
Have a look and see what you think: https://github.com/Chris--A/PrintEx/pull/21