1

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.

Jon D.
  • 27
  • 2
  • You can alias it with `unsigned char *`, too. `unsigned char *p = &u32; p[1] = xxx;` -- note that this is implementation-defined and endianness will play a role. – S.S. Anne Nov 21 '19 at 18:45
  • Look up what a bit mask is; also the bit shift operators. – RamblinRose Nov 21 '19 at 18:45
  • 1
    zero 2nd msbyte: `value & 0xff00ffffu`; set 3rd msbyte to 42 (`0x2a`): `(value & 0xffff00ffu) | 0x00002a00u`. – pmg Nov 21 '19 at 18:46

3 Answers3

1

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.

hko
  • 548
  • 2
  • 19
  • 1
    `byte3 << 24` is prone to errors. Let’s suppose `int` is 32 bits in the C implementation. Since `byte3` is a `uint8_t`, it is narrower than `int`, so, when it is used in `byte3 << 24`, it is automatically promoted to `int`. Then, if it is 128 or greater, `byte3 << 24` overflows the maximum value of an `int`. In C, the behavior of overflowing signed integer arithmetic is not defined. The implementation may trap, get the right answer, get the wrong answer, or do something else. If the compiler optimizes aggressively and can detect an overflow at compile time, it may remove this code completely. – Eric Postpischil Nov 21 '19 at 20:06
  • @Eric, thanks for pointing that out. I fixed my code by casting it to uint32_t value before the shift. This should solve it. – hko Nov 21 '19 at 20:47
0

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.

  • It's actually on old homework that I didn't finish. Now I'm just trying to study for my final exam. – Jon D. Nov 21 '19 at 19:05
0

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.

0x6261627564
  • 134
  • 1
  • 4