Datatype conversion (unsigned long to byte array)

Hello!

My name is Stefan and I am new in this forum. I am from Germany and I like electronics and making things with arduino. My programming knowledge is somewhat limited but I do my best :slight_smile:

I have a question about data conversion and a strange behavior I have observed in the following code. I´d like to convert a unsigned long number into an array of four bytes.
The conversion works fine but the reconversion into a unsigned long number is strange and I don´t understand it. I´m sure it is easy but I couldn´t find where the trick is.
Here is the code:

byte timearray[4];
unsigned long zeit; 
unsigned long zeit2;
void setup() {
  Serial.begin(9600);
}
void loop() {
    zeit = 0xFFAABB11;
    Serial.print("Time: ");
    Serial.println(zeit, HEX);
    byte_con(zeit);
    Serial.print ("0. Byte: ");
    Serial.println (timearray[0], HEX);
    Serial.print ("1. Byte: ");
    Serial.println (timearray[1], HEX);
    Serial.print ("2. Byte: ");
    Serial.println (timearray[2], HEX);
    Serial.print ("3. Byte: ");
    Serial.println (timearray[3], HEX);

    Serial.println() ;

    Serial.print ("0. Byte (weighted): ");
    Serial.println (timearray[0], HEX);
    Serial.print ("1. Byte (weighted): ");
    Serial.println (timearray[1] * 0x100, HEX);
    Serial.print ("2. Byte (weighted): ");
    Serial.println (timearray[2] * 0x10000, HEX);
    Serial.print ("3. Byte (weighted): ");
    Serial.println (timearray[3] * 0x1000000, HEX);
    Serial.println ();
    Serial.print ("2. Byte (weighted and corrected): ");
    Serial.println (((timearray[1] * 0x100)- 0xFFFF0000), HEX);
    zeit2 = timearray[0] + ((timearray[1] * 0x100)- 0xFFFF0000) + ( timearray[2] * 0x10000) + (timearray[3] * 0x1000000);
    Serial.println();
    Serial.print ("Zeit2 (reconstructed): ");    
    Serial.println (zeit2, HEX);
    Serial.println();
    Serial.println();

    while (true){
      };
}

void byte_con (unsigned long zahl){
  
    unsigned long a = zahl % 0x100;
    unsigned long b = (zahl % 0x10000 - a)/0x100;
    unsigned long c = (zahl % 0x1000000 - (a + b))/0x10000;
    unsigned long d = (zahl % 0x100000000 - (a + b + c))/0x1000000;
    timearray[0] = byte (a);
    timearray[1] = byte (b);
    timearray[2] = byte (c);
    timearray[3] = byte (d);
    }

The results in the console are:
Time: FFAABB11
0. Byte: 11

  1. Byte: BB

  2. Byte: AA

  3. Byte: FF

  4. Byte (weighted): 11

  5. Byte (weighted): FFFFBB00

  6. Byte (weighted): AA0000

  7. Byte (weighted): FF000000

  8. Byte (weighted and corrected): BB00

Zeit2 (reconstructed): FFAABB11


Why is the second byte FFFFBB00 and not BB00 and why do I have to correct it by substracting 0xFFFF0000 to get the correct value. I assume it is related to the data types. But what is the reason? Could someone help me in this issue.

Best regards

Stefan

Test_Byte_Conversion.ino (1.67 KB)

Why is the second byte FFFFBB00 and not BB00

This is the code:

    Serial.println (timearray[1] * 0x100, HEX);

What type are you printing? The first argument is timearray[1] * 0x100. What type is that?

timearray[1] is a byte. 0x100 is NOT. So, the result of the multiplication is a ? You must control the type, by using an intermediate variable, so that you can KNOW which overload of the print() method will be called.

OK, I understand, BUT:

Why is this only relevant for the second expression

Serial.println (timearray[1] * 0x100, HEX);

where the result is wrong and not for third and forth?
With the latest two the result is right.

Anyway:
If I use the following code (with data conversion to "long" of the byte array):

    zeit = 0xFFAABB11;
 
    Serial.print ("0. Byte (weighted): ");
    Serial.println (long (timearray[0]), HEX);
    Serial.print ("1. Byte (weighted): ");
    Serial.println ((long (timearray[1]) * 0x100), HEX);
    Serial.print ("2. Byte (weighted): ");
    Serial.println ((long (timearray[2]) * 0x10000), HEX);
    Serial.print ("3. Byte (weighted): ");
    Serial.println ((long (timearray[3]) * 0x1000000), HEX);
    Serial.println ();
    zeit2 = long (timearray[0]) + long (timearray[1]) * 0x100 + long(timearray[2]) * 0x10000 + long (timearray[3]) * 0x1000000;
    Serial.println();
    Serial.print ("Zeit2 (reconstructed): ");    
    Serial.println (zeit2, HEX);
    Serial.println();
    Serial.println();

the values are correct:


Time: FFAABB11
0. Byte: 11

  1. Byte: BB

  2. Byte: AA

  3. Byte: FF

  4. Byte (weighted): 11

  5. Byte (weighted): BB00

  6. Byte (weighted): AA0000

  7. Byte (weighted): FF000000

Zeit2 (reconstructed): FFAABB11


Thanks a lot for your help!

Regards
Stefan

where the result is wrong and not for third and forth?
With the latest two the result is right.

It isn't wrong. You have not answered the question. What TYPE are you printing?

The compiler is going to use the smallest type possible if you don't help it out by typing everything. Since 0x100 fits in an int, and the byte fits in an int, the result, after multiplication, is stored in an int. But, the value exceeds the limits of an int, so the value is negative.

HEX values are, by definition, unsigned, to the unsigned long version of print() is used, but the sign bit is set, so you get the FFFF up front.

If YOU stored the result of the multiplication in a variable of type long, or cast the byte to long, the compiler would not use an int for the intermediate type, and the result would print as you expect.

Thanks very much Paul for the explanation!
If I convert everything to long, the results are ok!

Regards
Stefan

Converting a long, signed or unsigned, to a byte array using a union is so much simpler.