unsigned long problem [SOLVED] - Page 1
Forum section: electronics / beginners

author: Raj
author_rank: Frequent Contributor
timestamp: September 21, 2017, 04:58:17 pm
content: i've been(banging my head against the wall) trying to debug my arduino (yeah,go on, call me a noob)when I type-unsigned long reading = 0;reading =0+ (0xFF00>> 8 );Serial.print(reading);I get 255, as expectedwhen i typeunsigned long reading = 0xFF00;Serial.print(reading);I get 65280but when I typeunsigned long reading = 0;reading =0+ (0xFF<< 8 );Serial.print(reading);I get 4294967040 instead of 65280try it- if you run this-void setup() {Serial.begin(9600);unsigned long reading = 0;reading =0+ (0xFF00>> 8 );Serial.println(reading);reading = 0xFF00;Serial.println(reading);reading =0+ (0xFF<< 8 );Serial.println(reading);Serial.println("blah");}you get255652804294967040blahinstead of2556528065280

author: Andy Watson
author_rank: Super Contributor
timestamp: September 21, 2017, 05:10:44 pm
content: It is treating the 0xFF as a signed value (probably defaulting to signed integer). The left shift causes it to be signed extended to FFFFFF00. You need to cast the original FF as unsigned int.

author: IanB
author_rank: Super Contributor
timestamp: September 21, 2017, 05:12:53 pm
content: It's caused by promotion rules. When you write the 8-bit constant 0xFF while you are doing 32-bit arithmetic the compiler is promoting it to a 32-bit constant 0xFFFFFFFF, which is 2^32. When you now shift this left by 8 bits, you get 0xFFFFFF00, which is 42494967040 in decimal.I don't know why your 16-bit constants like 0xFF00 didn't get promoted similarly. I would have to do a lot of reading of documentation to find that out.If you are doing arithmetic with unsigned long (32 bits), then make sure you write all your constants as 32-bit constants. Write 0x000000FF rather than 0xFF.

author: Jeroen3
author_rank: Super Contributor
timestamp: September 21, 2017, 05:15:16 pm
content: Try 0xFFu

author: Raj
author_rank: Frequent Contributor
timestamp: September 21, 2017, 05:22:18 pm
content: Ah, finally got it to work bu by changingunsigned longtounsigned intnowreading = 0xFF;reading= reading*256;Serial.println(reading);gives me 65280

author: Ian.M
author_rank: Super Contributor
timestamp: September 21, 2017, 05:30:44 pm
content: 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 seehttp://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:Code: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.