How do I change the value of a single byte in a uint32_t variable?

2.5k Views Asked by At

I have an assignment that requires me to read in a picture file as uint32_t variables for each pixel (3 bytes for color and 1 for saturation). I'm then supposed to filter the picture in various ways, such as a red filter where you set all the blue and green bytes to 0. I'm struggling to figure out how to alter the 4 individual bytes in the uint32_t variable.

3

There are 3 best solutions below

1
Dillon Nichols On

This popular answer describes how to modify a single bit. From there, you can expand it to operate on a byte (8 bits). Since this is homework, I don't want to completely answer it for you, but comment back if you still can't get it.

2
hko On

With bit shifting:

uint32_t pixel = 0;
uint8_t byte0 = 1, byte1 = 2, byte2 = 3, byte3 = 4;

pixel = (pixel & 0xFFFFFF00) |  byte0;
pixel = (pixel & 0xFFFF00FF) | ((uint32_t)byte1 <<  8);
pixel = (pixel & 0xFF00FFFF) | ((uint32_t)byte2 << 16);
pixel = (pixel & 0x00FFFFFF) | ((uint32_t)byte3 << 24);

printf("0x%x\n", pixel); /* --> 0x4030201 */

With a union:

typedef union pixel_s {
    uint32_t uint32_value;
    uint8_t uint8_value[4]; 
} pixel_t;

pixel_t pixel;
uint8_t byte0 = 1, byte1 = 2, byte2 = 3, byte3 = 4;

pixel.uint8_value[0] = byte0;
pixel.uint8_value[1] = byte1;
pixel.uint8_value[2] = byte2;
pixel.uint8_value[3] = byte3;

printf("0x%x\n", pixel.uint32_value); /* --> 0x4030201 */

As others mentioned this is machine depended. But most likely you are using x86 or x86_64, so it will be little endian. And the code above is for little endian.

0
0x6261627564 On

You can also use preprocessing macro to modify a certain byte inside a variable. Maybe it is provides you a more flexible solution.

#define SET_BYTE(INPUT, VALUE, POSITION)   (INPUT=(VALUE<<(POSITION<<3))|(INPUT&(0xFFFFFFFF^(0xFF<<(POSITION<<3)))))

where INPUT is the data what you wish to modify, VALUE is the new value and the POSITION is the byte position of the value.

Usage:

unsigned long data = 0xFFFFFFFF;
SET_BYTE(data , 0xAA, 2); /* set 0xAA to byte position 2; data = 0xFFAAFFFFFF */

Most probably my definition seems a bit messy but the following happens: The (INPUT&(0xFFFFFFFF^(0xFF<<(POSITION<<3)))) part of the macro creates a 0x00 bitmask on the correct byte position and clears the byte. Then the (VALUE<<(POSITION<<3)) set the new value on the correct place. Finally we logically or the bitmask with the new value.