Help with converting 4 bytes to a long

Hi,

I am having trouble converting 4 bytes to a long. I have 4 different methods and only 2 of them seem to be working.

Method 1 and 2 are from the forum ( http://forum.arduino.cc/index.php?topic=71030.0 )(can’t find the other link). Method 3 is from the Arduino Cookbook ( Inkling ) and method 4 is from http://stackoverflow.com/questions/11295728/convert-bytes-in-a-c-array-as-longs.

Although method 3 works, I simply copied and pasted it and I can’t say I understand what is happening

Why do methods 1 and 2 not work? Also, to me they look the same but I get different results?

/*
unsigned int = 0 to 65,535 
unsigned long = 0 to 4,294,967,295 
*/
#define makeLong(hi, low) (((long) hi) << 16 | (low))
#define highWord(w) ((w) >> 16)
#define lowWord(w) ((w) & 0xffff)

unsigned long val[] = { 0xFF, 0xFFFF, 0xFFFFFF, 0xFEFFFFFF ,0xFFFFFFFF, 0xFEFEFEFE  };
unsigned long val2 = 0;
byte buf[4];

void setup() 
{
Serial.begin(9600); 
while (!Serial)   {  ;   }

for (int i=0; i<6; i++)
{
    Serial.println ();
    Serial.println ("----------------------------");
    Serial.println ("Original value");
    
    buf[0] = (byte) ((val[i] >> 24) & 0xff);
    buf[1] = (byte) ((val[i] >> 16) & 0xff);
    buf[2] = (byte) ((val[i] >> 8) & 0xff);
    buf[3] = (byte) ( val[i] & 0xff);  
    Serial.print ("Long DEC = "); Serial.println (val[i]);  
    Serial.print ("Long HEX = "); Serial.println (val[i],HEX);  
    Serial.println ();   
  
    Serial.print ("buf0 = "); Serial.print (buf[0]); Serial.print ("  = "); Serial.println (buf[0], HEX); 
    Serial.print ("buf1 = "); Serial.print (buf[1]); Serial.print ("  = "); Serial.println (buf[1], HEX);  
    Serial.print ("buf2 = "); Serial.print (buf[2]); Serial.print ("  = "); Serial.println (buf[2], HEX);  
    Serial.print ("buf3 = "); Serial.print (buf[3]); Serial.print ("  = "); Serial.println (buf[3], HEX);  


    Serial.println ();     
    Serial.println ("New values"); 

    Serial.println ("-- method 1 --");
    val2=0;
    val2 = val2 + (unsigned long) buf[0] << 24;
    val2 = val2 + (unsigned long) buf[1] << 16;
    val2 = val2 + (unsigned long) buf[2] << 8;
    val2 = val2 + (unsigned long) buf[3];
    Serial.print ("1. New Long DEC = "); Serial.println (val2);  
    Serial.print ("1. New Long HEX = "); Serial.println (val2,HEX);  
 
 
    
    Serial.println ("-- method 2 --");
    val2=0;
    val2 = (unsigned long)(buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];    
    Serial.print ("2. Long DEC = ");  Serial.println (val2);  
    Serial.print ("2. Long HEX = "); Serial.println (val2,HEX);      
 
 
 
    Serial.println ("-- method 3 --");
    unsigned int hiWord = (unsigned int) word( buf[0], buf[1]); 
    unsigned int loWord = (unsigned int) word( buf[2], buf[3]); 
    val2 = (unsigned long) makeLong( hiWord, loWord);
    Serial.print ("lo = HEX "); Serial.println (loWord,HEX); 
    Serial.print ("hi = HEX "); Serial.println (hiWord,HEX); 
    Serial.print ("3. Long DEC = ");  Serial.println (val2);  
    Serial.print ("3. Long HEX = "); Serial.println (val2,HEX);  


    Serial.println ("-- method 4 --");
    val2 = buf[0];
    val2 = (val2 <<8) + buf[1];
    val2 = (val2 <<8) + buf[2];
    val2 = (val2 <<8) + buf[3];
    Serial.print ("4. Long DEC = ");  Serial.println (val2);  
    Serial.print ("4. Long HEX = "); Serial.println (val2, HEX);  

}


}   
// end set up --------------------------------------------------------------


void loop(){}

The results:

----------------------------
Original value
Long DEC = 255
Long HEX = FF

buf0 = 0  = 0
buf1 = 0  = 0
buf2 = 0  = 0
buf3 = 255  = FF

New values
-- method 1 --
1. New Long DEC = 255
1. New Long HEX = FF
-- method 2 --
2. Long DEC = 255
2. Long HEX = FF
-- method 3 --
lo = HEX FF
hi = HEX 0
3. Long DEC = 255
3. Long HEX = FF
-- method 4 --
4. Long DEC = 255
4. Long HEX = FF

----------------------------
Original value
Long DEC = 65535
Long HEX = FFFF

buf0 = 0  = 0
buf1 = 0  = 0
buf2 = 255  = FF
buf3 = 255  = FF

New values
-- method 1 --
1. New Long DEC = 65535
1. New Long HEX = FFFF
-- method 2 --
2. Long DEC = 4294967295
2. Long HEX = FFFFFFFF
-- method 3 --
lo = HEX FFFF
hi = HEX 0
3. Long DEC = 65535
3. Long HEX = FFFF
-- method 4 --
4. Long DEC = 65535
4. Long HEX = FFFF

----------------------------
Original value
Long DEC = 16777215
Long HEX = FFFFFF

buf0 = 0  = 0
buf1 = 255  = FF
buf2 = 255  = FF
buf3 = 255  = FF

New values
-- method 1 --
1. New Long DEC = 4278255615
1. New Long HEX = FF00FFFF
-- method 2 --
2. Long DEC = 4294967295
2. Long HEX = FFFFFFFF
-- method 3 --
lo = HEX FFFF
hi = HEX FF
3. Long DEC = 16777215
3. Long HEX = FFFFFF
-- method 4 --
4. Long DEC = 16777215
4. Long HEX = FFFFFF

----------------------------
Original value
Long DEC = 4278190079
Long HEX = FEFFFFFF

buf0 = 254  = FE
buf1 = 255  = FF
buf2 = 255  = FF
buf3 = 255  = FF

New values
-- method 1 --
1. New Long DEC = 4278255615
1. New Long HEX = FF00FFFF
-- method 2 --
2. Long DEC = 4294967295
2. Long HEX = FFFFFFFF
-- method 3 --
lo = HEX FFFF
hi = HEX FEFF
3. Long DEC = 4278190079
3. Long HEX = FEFFFFFF
-- method 4 --
4. Long DEC = 4278190079
4. Long HEX = FEFFFFFF

----------------------------
Original value
Long DEC = 4294967295
Long HEX = FFFFFFFF

buf0 = 255  = FF
buf1 = 255  = FF
buf2 = 255  = FF
buf3 = 255  = FF

New values
-- method 1 --
1. New Long DEC = 4278255615
1. New Long HEX = FF00FFFF
-- method 2 --
2. Long DEC = 4294967295
2. Long HEX = FFFFFFFF
-- method 3 --
lo = HEX FFFF
hi = HEX FFFF
3. Long DEC = 4294967295
3. Long HEX = FFFFFFFF
-- method 4 --
4. Long DEC = 4294967295
4. Long HEX = FFFFFFFF

----------------------------
Original value
Long DEC = 4278124286
Long HEX = FEFEFEFE

buf0 = 254  = FE
buf1 = 254  = FE
buf2 = 254  = FE
buf3 = 254  = FE

New values
-- method 1 --
1. New Long DEC = 4261478142
1. New Long HEX = FE00FEFE
-- method 2 --
2. Long DEC = 4294967038
2. Long HEX = FFFFFEFE
-- method 3 --
lo = HEX FEFE
hi = HEX FEFE
3. Long DEC = 4278124286
3. Long HEX = FEFEFEFE
-- method 4 --
4. Long DEC = 4278124286
4. Long HEX = FEFEFEFE

arithemetic binds tighter than shifts:

    val2=0;
    val2 = val2 + (unsigned long) buf[0] << 24;
    val2 = val2 + (unsigned long) buf[1] << 16;
    val2 = val2 + (unsigned long) buf[2] << 8;
    val2 = val2 + (unsigned long) buf[3];

is adding val2 to buf[n]. then shifting the result.

Correct:

    val2=0;
    val2 = val2 + ((unsigned long) buf[0] << 24);
    val2 = val2 + ((unsigned long) buf[1] << 16);
    val2 = val2 + ((unsigned long) buf[2] << 8);
    val2 = val2 + ((unsigned long) buf[3]);

Simpler, cleaner:

    val2 = (unsigned long) buf[0] << 24 ;
    val2 |= (unsigned long) buf[1] << 16 ;
    val2 |= (unsigned long) buf[2] << 8 ;
    val2 |= (unsigned long) buf[3] ;

Or if you are happy to be limited to the endianness of the processor:

  val2 = * ((unsigned long *) buf) ;

The thing you have to be careful about, is negative numbers.

The thing you have to be careful about, is negative numbers.

In unsigned long variables?

PaulS:

The thing you have to be careful about, is negative numbers.

In unsigned long variables?

Yeer they are the worst kind of negative numbers.

MartynC:
Hi,

I am having trouble converting 4 bytes to a long. I have 4 different methods and only 2 of them seem to be working.

        uint8_8 x; /* generic */
        uint32_t long_val = 0; /* initialize accumulator */
        for (x = 0; x < 4; x++) {
                long_val *= 256;
                long_val += buffer[0+x]; /* accumulate value (big-endian) */
                long_val += buffer[3-x]; /* accumulate value (little-endian) */
        }
        /* now "long_val" is the 32 bit value of "buffer[0] thru buffer[3]" */

Note the “big endian” and “little endian” lines - you use one or the other - not both - depending on if your data is little of big endian.

Example:

Original value = 0x12345678
In the buffer:
Big-endian = 0x12, 0x34, 0x56, 0x78
Little-endian = 0x78, 0x56, 0x34, 0x12

Hope this helps.

MarkT:
arithemetic binds tighter than shifts:

    val2=0;

val2 = val2 + (unsigned long) buf[0] << 24;
    val2 = val2 + (unsigned long) buf[1] << 16;
    val2 = val2 + (unsigned long) buf[2] << 8;
    val2 = val2 + (unsigned long) buf[3];



is adding val2 to buf[n]. then shifting the result.

Correct:


val2=0;
    val2 = val2 + ((unsigned long) buf[0] << 24);
    val2 = val2 + ((unsigned long) buf[1] << 16);
    val2 = val2 + ((unsigned long) buf[2] << 8);
    val2 = val2 + ((unsigned long) buf[3]);




Simpler, cleaner:


val2 = (unsigned long) buf[0] << 24 ;
    val2 |= (unsigned long) buf[1] << 16 ;
    val2 |= (unsigned long) buf[2] << 8 ;
    val2 |= (unsigned long) buf[3] ;




Or if you are happy to be limited to the endianness of the processor:


val2 = * ((unsigned long *) buf) ;

Many thanks.

MarkT:
Or if you are happy to be limited to the endianness of the processor:

  val2 = * ((unsigned long *) buf) ;

Wow! Never thought to do it this way. Very nice! Another useful bit of info stored in the Mark I Cranial Computer!

Krupski:

MarkT:
Or if you are happy to be limited to the endianness of the processor:

  val2 = * ((unsigned long *) buf) ;

Wow! Never thought to do it this way. Very nice! Another useful bit of info stored in the Mark I Cranial Computer!

Are you kidding? I don't have a clue how this way works and don't even want to know. :wink:
The other methods are something I can 'see' how they work and I don't mind a little extra
one typing in my sketch.

MarkT:
Or if you are happy to be limited to the endianness of the processor:

  val2 = * ((unsigned long *) buf) ;

One more option is to use C union. Something like

union {
  byte bytes[4];
  unsigned long number;
} magic_buffer;

magic_buffer.bytes[0] = ??
magic_buffer.bytes[1] = ??
magic_buffer.bytes[2] = ??
magic_buffer.bytes[3] = ??

Serial.println(magic_buffer.number);