C defaults to signed integer maths unless you tell it otherwise. Officially it doesn't 'snoop' across the equals sign to see what you are doing with the result
*. C integer promotion rules are a bit tricky and there is no substitute for studying the standard or K&R. Also see
http://c-faq.com/expr/preservingrules.html0xFF is 255, an integer, its small enough to fit in a singed integer so that's what it is taken as. <<8 causes an overflow, its now -256. If you enter it as 0xFF00, the same bit pattern, its too large to fit in a signed integer so the compiler uses a signed long. When the signed integer -256 is assigned to a long, its sign extended so its still -256. -256 in a long is the same bit pattern as 0xFFFFFF00, and if you dump that into an unsigned long you get 4294967040.
To avoid problems, you need to force the calculation to use a type compatible with the target size and type. The easiest would be:
unsigned long reading = 0;
reading =0+ (0xFFUL<< 8 );
Serial.print(reading);
Note the 'UL' suffix on the value being shifted - that tells the compiler its an unsigned long, so in this calculation it never overflows and cant be sign extended.
* smarter compilers skip calculating high bytes that will be lost to truncation, but the final result must be identical to performing the full calculation.