Output not as expected (uint32_t to uint8_t)

Hi All,

I’m running the code below on a ESP8266 and my output is not what I expect. Am I doing something silly or is this because of the 32bit/16bit instruction set?

The code is below:

int8_t bmp_header[8];
int32_t color_1 = 0x00FFFFFF;
int32_t color_2 = 0x0000FF00;


void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Serial.println();
}

void loop() {

  for(int8_t j=0; j<4; j++)
    {
      bmp_header[j]=((color_1 >> j*8) & 0xFF);
    }
  for(int8_t j=0; j<4; j++)
    {
      bmp_header[j+4]=((color_2 >> j*8) & 0xFF);
    }

  for(int8_t j=0; j<8; j++)
    {
      Serial.print(bmp_header[j], HEX);
      Serial.println();
    }

Serial.println();
delay(5000);
}

The output is

FFFFFFFF
FFFFFFFF
FFFFFFFF
0
0
FFFFFFFF
0
0

What am I doing with this code?
A: The code is taking a 32bit color variable and separating it into 4 bytes (RGBW). I’m then printing each element of the array. There are two colors, so a total of 8 bytes.

Why do I think it is not working?
A: I’m expecting a single byte (8 bit) represented as two hex characters (0xFF or 0x00)

Other observations:
if I use bmp_header[j+4]=((color_2 >> j*8) & 0x0F); rather than bmp_header[j+4]=((color_2 >> j*8) & 0xFF); I get one single Hex character (Either F or 0).

Many Thanks in advance!

when you use a 32 bit number it will not fit in 8 bit so you must convert it to byte or int.

shooter:
when you use a 32 bit number it will not fit in 8 bit so you must convert it to byte or int.

Thanks. I tried casting it, but makes no difference to the output

bmp_header[j]=(int8_t((color_1 >> j*8) & 0xFF));

There is no “print” overload for int8_t, int:

Therefore, the compiler selects print(int, int). Since it is a signed number, it is sign extended to 32 bits, because if you have -1 as a int8_t, it’s 0xFF, but as an int32_t, it’s 0xFFFFFFFF, not 0x000000FF.

When printing, you can cast it to uint8_t, so it’s not sign extended.

Serial.print((uint8_t)bmp_header[j], HEX);

Pieter

This looks right:

#include <Arduino.h>
uint8_t bmp_header[8];
uint32_t color_1 = 0x00FFFFFF;
uint32_t color_2 = 0x0000FF00;


void setup() {
  Serial.begin(115200);
  delay(1000);

  for (int8_t j = 0; j < 4; j++) {
    bmp_header[j] = ((color_1 >> j * 8) & 0xFF);
  }

  for (int8_t j = 0; j < 4; j++) {
    bmp_header[j + 4] = ((color_2 >> j * 8) & 0xFF);
  }

  Serial.println(color_1, HEX);
  for (uint8_t j = 0; j < 4; j++) {
    Serial.println(bmp_header[j], HEX);
  }

  Serial.println();
  Serial.println(color_2, HEX);
  for (uint8_t j = 0; j < 4; j++) {
    Serial.print(bmp_header[j + 4], HEX);
    Serial.println();
  }
}

void loop() {
}
FFFFFF
FF
FF
FF
0

FF00
0
FF
0
0

casemod:
Thanks. I tried casting it, but makes no difference to the output

bmp_header[j]=(int8_t((color_1 >> j*8) & 0xFF));

You were casting to the type of the destination variable.
What did you think that would do?

PieterP:
There is no "print" overload for int8_t, int:
Arduino/Print.h at e77f96c3e14c29714c072a7784614a3cae0abd47 · esp8266/Arduino · GitHub
Therefore, the compiler selects print(int, int). Since it is a signed number, it is sign extended to 32 bits, because if you have -1 as a int8_t, it's 0xFF, but as an int32_t, it's 0xFFFFFFFF, not 0x000000FF.

When printing, you can cast it to uint8_t, so it's not sign extended.

Serial.print((uint8_t)bmp_header[j], HEX);

Pieter

Ah, that is very helpful indeed!

gfvalvo:
This looks right:[...]

Yes, changing to unsigned seems to do!

TheMemberFormerlyKnownAsAWOL:
You were casting to the type of the destination variable.
What did you think that would do?

cap the output to 8 bit, rather than 32.

casemod:
cap the output to 8 bit, rather than 32.

But you can only save 8, so it doesn't matter.