char w = 'A';
unsigned char x = 'A';
int8_t y = 65;
uint8_t z = 65;
Serial.println (w);
Serial.println (x);
Serial.println (y);
Serial.println (z);
In my opinion, the 4 print statements, in order, should yield:
A A 65 65
What I get, however, is this:
A 65 65 65
I think this is wrong because the first two are chars. And since "A" (ascii 65) is within the bounds of a signed 8 bit variable, both char and unsigned char should print "A".
Am I wrong? If so, please explain why so I can understand it.
I think this is wrong because the first two are chars.
No. The first is a char. The other is not.
The Print class does not have an overload for print() that handles unsigned char. So, the nearest suitable function is used, instead, which is uint8_t, which is why you see 65.
I think this is wrong because the first two are chars.
No. The first is a char. The other is not.
The Print class does not have an overload for print() that handles unsigned char. So, the nearest suitable function is used, instead, which is uint8_t, which is why you see 65.
OK, maybe I didn't phrase the OP correctly. I know that there isn't a function in Print.cpp to handle an unsigned char.
What I'm asking is, "rightfully", shouldn't a char print as a letter (or a character) and not as an integer number?
There seems to be no difference between "char 65" and "unsigned char 65". Both are 0b01101001 in memory.
And in regards to your quote in blue, why is an unsigned char not a char (i.e. a letter character)?
Lastly, am I correct in saying that a uint8_t is the same thing as an unsigned char and an int8_t is the same as a signed char?
I am sure that by the time this function gets its data, the "unsigned char" you wrote is long gone, since that is a compiler thing. All the function knows is that it is being passed an unsigned 8 bit data type, and handles it accordingly. The only way to handle this like you want is to write a version that explicitly handles unsigned chars, so the compiler knows to associate it with a "char" at compile time.
KeithRB:
I am sure that by the time this function gets its data, the "unsigned char" you wrote is long gone, since that is a compiler thing. All the function knows is that it is being passed an unsigned 8 bit data type, and handles it accordingly. The only way to handle this like you want is to write a version that explicitly handles unsigned chars, so the compiler knows to associate it with a "char" at compile time.
Honestly... that's what I'm trying to do. I'm "fixing" Print.cpp (and of course Print.h) in several ways.
The "printNumber" function is re-done so-as not to use a buffer, support for 64 bit (long long and unsigned long long) is being added and finally I'm wanting to properly handle 8 bit chars and ints (signed and unsigned).
For example, here's the "printNumber" function that doesn't use a buffer (which would be 72 bytes(!) for a long-long):
size_t Print::printNumber (unsigned long long value, uint8_t base)
{
size_t n = 0;
uint8_t idx;
uint8_t pow;
unsigned long long val;
pow = 0;
val = value;
// constrain base 2...16
base = base < 2 ? 2 : base > 16 ? 16 : base;
while (val) {
val /= base;
pow++;
}
val = value;
while (pow--) {
idx = val / intPower (base, pow);
val -= idx * intPower (base, pow);
print ( * ("0123456789ABCDEF" + idx));
n++;
}
return n;
}
/// this function is private
size_t Print::intPower (uint8_t base, uint8_t exp)
{
int result = 1;
while (exp--) {
result *= base;
}
return result;
}
I'm also working on a complete driver for a vacuum fluorescent display and, of course, I need to provide complete PRINT and PRINTLN support. So I thought I would use the Arduino Print.cpp as a "model" for the VFD code and found that Print.cpp is a bloated mess. So first I have to fix Print, then on to the VFD code.
I think what I'll do is write my same test code, then compile it in GCC (Linux) and see how it handles each data type and use the same behavior for my code.
In the char case, there is an overload that handles char, so it knows it is a char.
In the unsigned char case, there is no explicit case, so it uses the underlying uint_8, so the "hint" that it should be treated as a char is gone, and it gets treated as a number.
KeithRB:
In the char case, there is an overload that handles char, so it knows it is a char.
In the unsigned char case, there is no explicit case, so it uses the underlying uint_8, so the "hint" that it should be treated as a char is gone, and it gets treated as a number.
Yes I know that. What I am saying is "intuitively", a "char" should print as a letter and an int should print as a number.
In the absence of a "%c" or "%s" printf modifier, how on earth does Print whether to print "A" or "65"???
At least it should make sense. If I use a char, I should expect "A". if I use an int, I should expect "65".
The way Print responds seems arbitrary and makes no sense.
It's pointless to tell me "this is what the existing code does" I know this already. What I want to know is how SHOULD it act?
but the point is, an unsigned char is not a char, it is not a character, it shouldn't be treated as one just because it has the word char in the name. 'Byte' and 'unsigned char' and 'uint8_t' are all the same. 'char' and 'int8_t' are the same.
In fact they are all just numbers.
If you want it to print an ASCII representation, use a 'char'. Or do this:
unsigned char bob = 32;
Serial.print((char)bob); //treat bob as a char.
OK... I'm determined to figure this thing out. I wrote a little piece of test code that simply prints which function is reached for various data types.
In other words, I did this (abbreviated form - but you get the idea):
Test::test (char c) { Serial.print ("CHAR reached"); }
Test::test (unsigned char c) { Serial.print ("UNSIGNED CHAR reached"); }
Test::test (int c) { Serial.print ("INT reached"); }
Test::test (unsigned int c) { Serial.print ("UNSIGNED INT reached"); }
When I threw the 4 data types at it (i.e. char, unsigned char, int8_t and uint8_t), what I got was:
How the Arduino print code is determining which format to use is beyond me.
IIRC, this was a explicit decision; go back to early versions and "unsigned char" and "char" were printed identically (producing "65", apparently.) But"char" in the arduino world is actually usually a character, while "unsigned char" was frequently actually a "byte" - a smaller integer used for code efficiency.
There was also "print(c, BYTE)", which is now deprecated in favor of "write(c)"