PrintEx icon indicating copy to clipboard operation
PrintEx copied to clipboard

basic_usage.ino and %n format specifier

Open bperrybap opened this issue 9 years ago • 11 comments

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.

bperrybap avatar Jul 22 '16 16:07 bperrybap

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.

Chris--A avatar Jul 25 '16 22:07 Chris--A

I've also overlooked the %p specifier, I might as well implement that too. This will force the repeat, and PROGMEM specifiers to change.

Chris--A avatar Jul 25 '16 23:07 Chris--A

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.

bperrybap avatar Jul 25 '16 23:07 bperrybap

I have been using this as my guide to what the correct options are: http://www.cplusplus.com/reference/cstdio/printf/

Chris--A avatar Jul 26 '16 00:07 Chris--A

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.

bperrybap avatar Jul 26 '16 00:07 bperrybap

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.

Chris--A avatar Jul 26 '16 00:07 Chris--A

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 );

Chris--A avatar Jul 26 '16 09:07 Chris--A

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.

bperrybap avatar Jul 26 '16 18:07 bperrybap

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.

bperrybap avatar Jul 26 '16 18:07 bperrybap

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.

Chris--A avatar Jul 27 '16 02:07 Chris--A

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

Chris--A avatar Jul 29 '16 02:07 Chris--A