Home > database >  C: Typecasting with bitfields reverses values?
C: Typecasting with bitfields reverses values?

Time:02-02

I am trying to cast a byte stream (raw data from serial port) into a structure for ease of use. I have managed to replicate the problem in a minimal working example:

#include <stdio.h>

typedef struct {
    unsigned int source: 4;
    unsigned int destination: 4;
    char payload[15];
} packet;

int main(void)
{
    // machine 9 sends a message to machine 10 (A)
    char raw[20] = {0x9A, 'H', 'e', 'l', 'l', 'o', '!', 0};
    packet *message = (packet *)raw;
    printf("machine %d ", message->source);
    printf("says '%s' to ", message->payload);
    printf("machine %d.\n", message->destination);
    return 0;
}

I would expect the field source to get 9 from 0x9A and destination to get A from 0x9A so that the output says:

machine 9 says 'Hello!' to machine 10.

But I get:

machine 10 says 'Hello!' to machine 9.

Any idea why this might be so?

CodePudding user response:

The issue is with the way you are interpreting the raw data as a packet structure. The fields source and destination are defined as 4-bit fields, which means they can only hold values between 0 and 15. However, when you cast the raw data to a packet pointer, you're interpreting the first byte of raw as an 8-bit integer, not as two 4-bit integers.

To get the desired behavior, you'll need to extract the values of source and destination from the first byte of the raw data and store them in separate variables before storing them in the packet structure. Here's one way to do it:

#include <stdio.h>

typedef struct {
unsigned int source: 4;
unsigned int destination: 4;
char payload[15];
} packet;

int main(void)
{
// machine 9 sends a message to machine 10 (A)
char raw[20] = {0x9A, 'H', 'e', 'l', 'l', 'o', '!', 0};
unsigned char source = raw[0] >> 4;
unsigned char destination = raw[0] & 0x0F;

packet message;
message.source = source;
message.destination = destination;
memcpy(message.payload, &raw[1], sizeof(message.payload));

printf("machine %d ", message.source);
printf("says '%s' to ", message.payload);
printf("machine %d.\n", message.destination);
return 0;
}

This code should produce the desired output:

machine 9 says 'Hello!' to machine 10.

CodePudding user response:

0x9A - lowest 4 bits A, highest 4 bits 9.

In your structure if you compile with GCC member source (occupying lower nibble) is assigned A and destination (occupying higher nibble) is assigned 9

So program output is correct.

  • Related