leftshift on unsigned long

byte b0 = 0x94;
byte b1 = 0x87;
byte b2 = 0x45;
byte b3 = 0x41;
unsigned long d = (b3<<24)|(b2<<16)|(b1<<8)|(b0);
Serial.println (d,HEX);

gives following output FFFF8794

what am I doing wrong ??

thanks for your help

Marthino:
what am I doing wrong ??

Probably shifting bytes too far without casting a compatible type. Shifted bits get lost before d gets them.
Try the same with b0-3 defined as unsigned long instead of byte.

Posting with out using code tags and not previewing your post :sunglasses:

Mark

:slight_smile: thanks igendel.... :slight_smile:

try
unsigned long d = ((uint32_t)b3<<24) | ((uint32_t)b2<<16) | ((uint32_t)b1<<8) | (b0);

I'm still not sure, though, where the FFFF in the beginning of the output came from.

igendel:
I'm still not sure, though, where the FFFF in the beginning of the output came from.

d = (b3 << 24) | (b2<<16) | (b1<< 8 ) | ( b0);

shift normally works on 16 bits signed ints

that means
(b3 << 24) | (b2<<16)

those bits are shifted to the eternal bitfields, leaving effectively
d = (b1<< 8 ) | ( b0);
please verify this in your code

as b1 == 0x87, the shifted int is 0x8700 // note the MSB is set!!!

When assigned to d this most significant bit (MSB) is extended to all higher bits of the unsigned long.

change b1 = 0x47 and you will notice the difference

robtillaart:
When assigned to d this most significant bit (MSB) is extended to all higher bits of the unsigned long.

Let me see if I understand... bits don't just "extend" - the implicit type there is signed, so when assigned to an unsigned it's treated as a two's complement?

Marthino:

  byte b0 = 0x94;

byte b1 = 0x87;
 byte b2 = 0x45;
 byte b3 = 0x41;
 unsigned long  d = (b3<<24)|(b2<<16)|(b1<<8)|(b0);
 Serial.println (d,HEX);



gives following output FFFF8794 

what am I doing wrong ??

The type 'unsigned char' (byte) gets promoted to type 'int' when used in an expression. Since all the parts to the right of the '=' are type 'int' the result gets converted to 'unsigned long' only on assignment. The first step in the conversion is to expand the 16-bit int to a 32-bit long. Since 'int' is signed the expansion does a sign extension. The 32-bit result is then converted from signed to unsigned (which does nothing) and saved in your unsigned long.

To fix the problem you can explicitly cast the bytes as unsigned long:

  unsigned long  d = ((unsigned long)b3<<24)|((unsigned long)b2<<16)|((unsigned long)b1<<8)|((unsigned long)b0);
  Serial.println (d,HEX);

It is probably sufficient to use unsigned long constants:

  unsigned long  d = (b3<<24UL) | (b2<<16UL) | (b1<<8UL) | (b0);
  Serial.println (d,HEX);