I'm working on a C project for a PIC microcontroller in MikroC and have a function:
void Write_SPI_32(unsigned long Address, unsigned long Data);
That only sometimes works:
Write_SPI_32(0x300000 12, 0b10001111000010100000000000000000); //Gives expected result
Write_SPI_32(0x300000 12, 0x8f0a0000); //Gives expected result
Write_SPI_32(0x300000 12, 2399797248); //Gives expected result
Write_SPI_32(0x300000 12, (2 << 30) | (120 << 21) | (160 << 12)); //Gives UNEXPECTED result
How am I managing to noob the bitwise math here?
CodePudding user response:
2 << 30
overflows a 32-bit int
, as the nominal result would be 231, but the largest value representable in int
would be 231−1, so the behavior is not defined by the C standard.
A typical behavior from a compiler would be that this produces the result −231 (the same bit pattern as 231 but interpreted with two’s complement), then the other operands (120 << 21
and so on) are ORed in. Then, when the argument is converted to a 64-bit unsigned long
to pass to Write_SPI_32
, this negative int
becomes an unsigned long
with its high 32 bits set.
You can use (unsigned long) 2 << 30
or 2ul << 30
. When shifting, it is often useful to cast the left operand to the ultimate destination type, so that the shift is performed in that type instead of in the default type that results from the integer promotions.