7
votes

I'm having a really strange inconsistancy.
I'm preparing for reading from binary files on Arduino (for a midi player, in case you were interested). If I try to combine 4 bytes on Arduino to a long, it gives me a wrong result.
However, if I use the equivalent code on PC, I get the correct value.

Input is: 0x12481248 (0x12, 0x48, 0x12, 0x48) (really a random number).

Arduino gives: 4680.

Code::Blocks gives: 306713160.

4680 is the same as 0x1248, and the result you get when you use an int instead of long on Arduino (2 bytes omitted).

Arduino code:

void setup(){
    Serial.begin(57600);
    char read1 = 0x12;
    char read2 = 0x48;
    char read3 = 0x12;
    char read4 = 0x48;
    unsigned long testint = read1<<24|read2<<16|read3<<8|read4;
    unsigned long testint2 = 306713160;
    Serial.println(testint);
    Serial.println(testint2);
}

void loop(){}

testint2 is to show that it isn't caused by Serial.println(). Serial Monitor output is indeed:

4680

306713160

C++ code:

#include <iostream>

using namespace std;

int main(){
    char read1 = 0x12;
    char read2 = 0x48;
    char read3 = 0x12;
    char read4 = 0x48;
    unsigned long testint = read1<<24|read2<<16|read3<<8|read4;
    cout << testint;
}

Any idea what's going on?

Also, does anyone know a better/prettier way of converting bytes with Arduino/SD library?

3

3 Answers

11
votes

On Arduino, int size is 16 bits.

In this line:

unsigned long testint = read1<<24|read2<<16|read3<<8|read4;

even if the result is stored in a unsigned long (32 bits), the bitwise operations are done on ints.

Change this line to:

unsigned long testint = (unsigned long)read1 << 24 
                      | (unsigned long)read2 << 16
                      | (unsigned long)read3 << 8
                      | (unsigned long)read4;
4
votes

I would expect the result 4680 (=0x1248) on any platform where sizeof(int)=2, and I think this is the case for arduino.

That's because (read1 << 24) gets implicitly converted to int (not long), so the upper two bytes get lost. Yout should convert read* to unsigned long first

0
votes

You can also use the following code:

uint8_t data[4];
data[0]=read4;
data[1]=read3;
data[2]=read2;
data[3]=read1;
unsigned long testint =*(unsigned long*)(&data);