bit shift and char cast

Hi there, I just encountered a very odd behaviour while writing a sketch for a arduino UNO. I wrote a simplified sketch that shows the problem I have.

char character;
int initNumb= 43690; //B1010101010101010
int integer;
void setup()
{
   Serial.begin(115200); 
}

void loop()
{
    integer = initNumb;
    integer = (integer>>8) & B11111111;
    Serial.print("Integer:   ");
    Serial.println(integer,BIN);
    
    character = integer;
    Serial.print("Character: ");
    Serial.println(character, BIN);
    Serial.println();
  
    delay(1000);


}

Whenever I Serial.print(character,BIN), the value on the Serial monitor appears as 11111111111111111111111110101010. I don't understand the logic of it. First of all, the result should be 10101010 as I AND the initial value with B11111111. Second of all, I dont understand how can such a big value be printed since a char is just a byte long numer. Does anyone understand what is going on?

int initNumb= 43690;

?

Google "sign extension"

A signed int can only cout up to 32000 and something.

No matter, the question is why a char shows a 32 bit number?

the range of int is -32768 to 32767 and since you are allocation more than 32767 so value change towards the -ive range of int. ie -32768. because of this you are getting negative value. so your intNumb contains 32767 - 43690 ie - 10923 in decimal since -ive sign is represented with 1 so 1's are appended at begining.

So it's negative value, so what! Why is char character a 32 bit binary number?

steinie44: So it's negative value, so what! Why is char character a 32 bit binary number?

You have all the source if you want to satisfy your curiosity.

size_t Print::print(unsigned char b, int base)
{
  return print((unsigned long) b, base);
}

You have all the source if you want to satisfy your curiosity.

I did.

I think this came up in another Thread not too long ago and the conclusion was that it is a "peculiarity" of the Arduino's print code which doesn't have variations for every datatype.

...R

BijendraSingh:
the range of int is -32768 to 32767 and since you are allocation more than 32767 so value change towards the -ive range of int. ie -32768.
because of this you are getting negative value. so your intNumb contains 32767 - 43690 ie - 10923 in decimal
since -ive sign is represented with 1 so 1’s are appended at begining.

AWOL:
You have all the source if you want to satisfy your curiosity.

size_t Print::print(unsigned char b, int base)

{
  return print((unsigned long) b, base);
}

Thank you guys, this makes a lot of sense. But there still is one thing I don’t understand: in the middle of the code I put

integer = (integer>>8) & B11111111;

This should make all the bits that are more significant than the 8th bit equal to zero. Am I wrong?

shesko: Thank you guys, this makes a lot of sense. But there still is one thing I don't understand: in the middle of the code I put

integer = (integer>>8) & B11111111;

This should make all the bits that are more significant than the 8th bit equal to zero. Am I wrong?

Yes, you are wrong.

Consider the 16 bit integer -16, represented in 2's complement as 0xfff0. Shift it down eight bits, and you get 0x00FF. AND it with 0xFF and you still have 0xFF.

AWOL: Yes, you are wrong.

Consider the 16 bit integer -16, represented in 2's complement as 0xfff0. Shift it down eight bits, and you get 0x00FF. AND it with 0xFF and you still have 0xFF.

That doesn't make my statement wrong. You still have 0xFF because you're ANDing it with FF... In othe words you're ANDing all the high bits with high bits. In your example, if you shift 0xFFF0 by four bits instead of eight, you get 0xFFF. If you then AND it with 0x0FF you should end up with 0xFF and not 0xFFF, right? So from my previous example: if I have 0xAAAA and AND it with 0xFF, I should be getting 0x0AA...

1010101010101010 &
0000000011111111 =
--------------------
0000000010101010

But instead I get 0xFFFFFFAA = B11111111111111111111111110101010.

Try this code:

unsigned char character;
unsigned int initNumb= 43690; //B1010101010101010
unsigned int integer;
void setup()
{
   Serial.begin(115200); 
}

void loop()
{
    integer = initNumb;
    integer = (integer>>8) & B11111111;
    Serial.print("Integer:   ");
    Serial.println(integer,BIN);
    
    character = integer;
    Serial.print("Character: ");
    Serial.println(character, BIN);
    Serial.println();
  
    delay(1000);


}

and try to explain the differences in the result.

And what about this?

unsigned char character;
int initNumb= 43690; //B1010101010101010
int integer;
void setup()
{
   Serial.begin(115200); 
}

void loop()
{
    integer = initNumb;
    integer = (integer>>8) & B11111111;
    Serial.print("Integer:   ");
    Serial.println(integer,BIN);
    
    character = integer;
    Serial.print("Character: ");
    Serial.println(character, BIN);
    Serial.println();
  
    delay(1000);

}

Here is my sketch edited a bit. Now the initial variabes are "long" and not "int" anymore. This means that the number is now positive.

char character;
long initNumb= 43690; //B1010101010101010
long integer;
void setup()
{
   Serial.begin(115200); 
}

void loop()
{
    integer = initNumb;
    integer = ( integer>>8 ) & B11111111;
    Serial.print("Integer:   ");
    Serial.print(integer,BIN);
    Serial.print (" i.e.  ");
    Serial.println(integer,HEX);
    
    character = integer;
    Serial.print("Character: ");
    Serial.print(character, BIN);
    Serial.print (" i.e.  ");
    Serial.println(character,HEX);
    
    character = character & 0xFF;
    Serial.print("Character ANDed with 0xFF = ");
    Serial.print(character, BIN);
    Serial.print (" i.e.  ");
    Serial.println(character,HEX);
    Serial.println();
  
    delay(5000);
}

The results are:

Integer: 10101010 i.e. AA Character: 11111111111111111111111110101010 i.e. FFFFFFAA Character ANDed with 0xFF = 11111111111111111111111110101010 i.e. FFFFFFAA

As you can see, when I print the "long" variable, the result is as desired. Once I assign the same value to a char and then print it, the result changes to 0xFFFFFFAA. Even after ANDing it again with 0xFF the result is the same.

Moderator edit: CODE TAGS.

But instead I get 0xFFFFFFAA = B11111111111111111111111110101010.

Because 0xAA is negative. Google "sign extension"

And this???

unsigned char char2;
char character;
int initNumb= 43690; //B1010101010101010
int integer;
void setup()
{
   Serial.begin(9600); 
}

void loop()
{
    integer = initNumb;
    integer = (integer>>8) & B11111111;
    Serial.print("Integer:    ");
    Serial.println(integer,BIN);
    
    char2 = integer;
    character = char2;
    Serial.print("Character : ");
    Serial.println(character, BIN);
    Serial.print("Character2: ");
    Serial.println(char2, BIN);
    Serial.println();
  
    delay(1000);
}

And if... what you see is not what you really have? (you need to interpret the information that the machine gives you)

EDIT: the result is:

Integer:    10101010
Character : 11111111111111111111111110101010
Character2: 10101010
int initNumb= 43690; //B1

A negative number.

(The "B" binary prefix macros are only for eight bit numbers - use "0bxxxx")

Genious! Thank you very much, I don't think I would have figured this out without you!

Only one more:

unsigned char char2;
char character;
int initNumb= 43690; //B1010101010101010
int integer;
void setup()
{
   Serial.begin(9600); 
}

void loop()
{
    integer = initNumb;
    integer = (integer>>7) & B11111111;
    Serial.print("Integer:    ");
    Serial.println(integer,BIN);
    
    char2 = integer;
    character = char2;
    Serial.print("Character : ");
    Serial.println(character, BIN);
    Serial.print("Character2: ");
    Serial.println(char2, BIN);
    Serial.println();
  
    delay(1000);
}

The return is:

Integer:    1010101
Character : 1010101
Character2: 1010101