long integer math mystery

If I run the following code the result, newnum, comes out right if the second byte is less than 0x80. If i run the code, replacing the 7f with 80 or greater the result is low by 0x1000. I do not understand. I thought that it had to do with the long being signed, but tried it with unsigned long and the result was the same. I figure the 0x1000 difference is a clue, but to what?

output with byte 2 less than 0x80 AABB7FDD DD 7F BB AA AABB7FDD

output with byte 2 0x80 or greater AABB80DD DD 80 BB AA AABA80DD

long num = 0xaabb7fdd;  0xaabb80dd has error
byte byt[5];

void setup()
  Serial.println(num, HEX);
  Serial.println(num, BIN);
  byt[0] = num;
  byt[1] = num>>8;
  byt[2] = num>>16;
  byt[3] = num>>24;
  Serial.print(byt[0], HEX);
  Serial.print("   ");
  Serial.print(byt[1], HEX);
  Serial.print("   ");
  Serial.print(byt[2], HEX);
  Serial.print("   ");
  Serial.println(byt[3], HEX);
  byt[4] = '\0';
  long newnum = (byt[3] * 16777216) + (byt[2] * 65536) + (byt[1] * 256) + byt[0];
  Serial.println(newnum, HEX);
  Serial.println(newnum, BIN);

void loop()


Google "sign extension"

I googled sign extension. My brain hurts. I'm taking a break.

Edit. Thanks for the clue, AWOL. I found a post that had an answer and am getting the results that I need. Just needed a clue what to look for.

Intermediate results in C are normally signed int unless both argments were unsigned.

If you calculate a byte times 256, that 256 is a signed int constant.

The correct way to build up a larger result from bytes is to use a variable
of the result type as the working space:

  long newnum = 0 ;
  for (byte i = 3 ; i >= 0 ; i--)
    newnum = (newnum << 8) | byt [i] ;  // byt value extended to long, not int, before the |

Then the intermediate results are always 32 bit long, and you never get a signbit
at position 15 (which is where it is for signed int).