Currently, `int x = -16; Serial.print(x, HEX);` prints FFFFFFF0, even though ints are 16 bits, so one would expect FFF0. This is because Print::print(int n, int base) converts the 16-bit int n to 32-bit long before printing, and then prints that long in two's complement. As a result, a 16-bit number has a 32-bit representation. But I think this behavior should be fixed to produce less unexpected results.
I can think of three possible solutions:
1. Convert signed char, short, int, and long to unsigned char, unsigned short, unsigned int, and unsigned long respectively for printing them in a base other than 10, and use 2's complement for negative numbers. print(-16,HEX) will print FFF0. This makes sense to those familiar with 2's complement, and C's printf("%x") (which actually prints unsigned ints).
2. Extend the behavior of base 10 to every other base: print negative numbers with a '-' followed by the absolute value, instead of making this a special case for base 10. print(-16,HEX) will print -10. This is how it works in Python and JavaScript, for example. If someone wants FFF0, explicit conversion to unsigned int is needed.
3. Leave it as it is now, and explain in detail in the documentation why this happens and how to properly handle it. print(-16,HEX) will print FFFFFFF0. If someone wants FFF0, explicit conversion to unsigned int is needed.
Personally I think the solution that makes most sense is number 2. It is the mathematically logical one, doesn't require users being familiar with 2's complement, and makes it easy to identify negative numbers (otherwise, if someone accidentally prints a negative, they might not understand the output they get and will be harder for them to identify the issue). And if they really wanted to print it in 2's complement, they will probably figure out naturally that they need to convert to unsigned int.
Furthermore, implementing this is as simple as *removing* a check for base == 10, so the resulting code is even simpler. I made a PR implementing this in https://github.com/arduino/Arduino/pull/4535 (which is no longer valid because Chainsaw).
What do you think is the most desirable behavior? 1, 2, or 3? I wanted to get some feedback from the mailing list before I redo the commit.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/b743ba13-bc2e-48d4-a12d-3d35b205b365%40arduino.cc.
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/CANoujwHTwDY7G5iAMtAnZCyWKkOB%3DzHXxm7b-te%3D4B7Qtg99Tw%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
To view this discussion on the web visit https://groups.google.com/a/arduino.cc/d/msgid/developers/9cf6568d-35c9-4151-9545-734f53b27aaa%40arduino.cc.
Honestly I think having separate formatting functions/classes makes more sense than delegating the formatting on the print() method; it would simplify things a lot and allow creating custom and more complex formatters. "Print the hex representation of x" (print(HEX(x))) looks better than "print x but in hex" (print(x, HEX)).
(Also, it would fit better with the idea of "print with variadic arguments" I proposed back in the day.)