venkysmarty
venkysmarty

Reputation: 11431

Parsing 32 bit integer in C program

I have a 32 bit integer, split into parts like this:

 --------------------------------------
 | Part1         | Part2    | Part 3  |
 --------------------------------------

Part 1 higher 16 bits. (Part 2 + Part 3) = lower 16 bits.

Part 2 is 10 bits and Part 3 is 6 bits

I need help on how do we read and update part 1, part2 and part 3 in C program.

Upvotes: 0

Views: 2729

Answers (4)

dubnde
dubnde

Reputation: 4441

Try cast to this structure

struct {
    uint32_t part_1:16;
    uint32_t part_2:10;
    uint32_t part_3:6;
} parts;

Could be the one below depending on endianness

  struct {
        uint32_t part_1:6;
        uint32_t part_2:10;
        uint32_t part_3:16;
    } parts;

Obviously not portable!

Since you need to read and update, a pointer will do. For example, if you 32bit value is called x, you do the following

parts *ptr = (parts *)&x;

ptr->part_2 = <part2 update>

Upvotes: 2

Santiago Alessandri
Santiago Alessandri

Reputation: 6855

The theory to be used behind this are and, or and shift operations with masks.

To access some bits of the integer, first create a mask where there are ones in the bits you want to be used. Now apply and and(&) operation between the mask and the integer. According to the behavior of the & the bits where the mask is 0 will be 0 and where the mask is 1 will have the value of that bit in the integer. Now that we have only the bits we want we align them to the right, that is done shifting the bits to the right the correct number of positions as to leave the rightmost bit of the mask in the less significant position of the byte.

To write in a part of a byte, we need fist to nullify what was in that part for that we use the negated mask that is used to read that part. Once that part is negated we apply an or(|) operation with the new value that must be aligned to that position.

To read:

unsigned int read_part_1(unsigned int composed) {
   return (composed & 0xffff0000) >> 16;
}

unsigned int read_part_2(unsigned int composed) {
   return (composed & 0x0000ffc0) >> 6;
}

unsigned int read_part_3(unsigned int composed) {
   return (composed & 0x0000003f);
}

To write(val aligned to the right):

unsigned int write_part_1(unsigned int composed, unsigned int val) {
   return (composed & ~0xffff0000) | ((val & 0x0000ffff) << 16);
}

unsigned int write_part_2(unsigned int composed, unsigned int val) {
   return (composed & ~0x0000ffc0) | ((val & 0x000003ff) << 10);
}

unsigned int write_part_3(unsigned int composed, unsigned int val) {
   return (composed & ~0x0000003f) | (val & 0x0000003f);
}

Upvotes: 1

Neera
Neera

Reputation: 1587

int i

To extract the individual parts

part1 = (i & 0xFFFF0000) >> 16

part2 = (i & 0x0000FFC0) >> 6

part3 = (i & 0x0000003F) 

To compose the integer

i = (part1 << 16) | (part2 << 6) | (part3)

Upvotes: 2

unwind
unwind

Reputation: 399949

Given an integer x with the above format, you can replace Part2 like this:

x = (x & ~(0x3ff << 6)) | (newPart2 << 6);

and Part3 like so:

x = (x & ~0x3f) | newPart3;

This assumes that both newPart2 and newPart3 are e.g. unsigned int with their new values right-adjusted.

Upvotes: 8

Related Questions