Simon Inns
Simon Inns

Reputation: 108

Adding structure to an array of char in C

I have a C program that receives a 64 byte array of char (which is passed via USB). Depending on the first byte (which indicates the command type) I want to 'impose' a structure over the char array to make the code clearer.

For example, if the command code is 10 I would expect something like:

struct
{
    uint8_t commandNumber;
    uint16_t xPos;
    uint16_t yPos;
    int32_t identificationNumber;
 } commandTen;

So I would like to cast my char packet[64] 'onto' commandTen and then access the fields using something like:

localVar = commandTenPacket->xPos;

How can this be achieved in C?

Thanks in advance!

Upvotes: 2

Views: 1645

Answers (3)

xQuare
xQuare

Reputation: 1323

There is a way using pointers. Let me try to explain it this way:

struct commandX {
   int x;
};
struct commandMessage {
   char[8] msg;
};

char* message = (char*) malloc(sizeof(char)*9); // this will allow us a struct 
                                                // size of 8 bytes, since the
                                                // first byte will store the
                                                // information on how to inter-
                                                // the memory (or you do it in
                                                // a different way).
// 1. determine your offset
//    in this case, it would be the length of the command on how to interpret.
//    basically, it has to be the count of bytes from the
//    beginning of your message to the start of your struct
int offset = sizeof(char) * 1;
// 2. read the command (that would be: message[0])
// 3. now get rid of the type information, so that you can address every byte
void* temp = (void*) message;
// 4.1 if it is commandX:
struct commandX *x_temp = (struct commandX*) (temp+offset);
    // use x_temp->x
// 4.2 if it is commandMessage:
struct commandMessage *msg_temp = (struct commandMessage*) (temp+offset)
   // use msg_temp->msg

Upvotes: 0

Jens Gustedt
Jens Gustedt

Reputation: 78923

First, as others said you'd have to ensure that your struct has no padding. Your compiler probably has an extension for that, #pragma pack or so.

Define a struct for each of your use cases, not a variable as in your example.

Then define a union

typedef union overlay overlay;

union overlay {
 uint8_t raw[64];
 struct type10 command10;
 struct type42 command42;
};

Now create a buffer of that type

overlay buffer;

Feed the "raw" part to your function that receives the data: getit(buffer.raw). And then

switch (buffer.raw[0]) {
 case 10: {
   // use buffer.command10
   break;
 }
 case 42: {
   // use buffer.command42
 }
}

This is guaranteed by the C standard to work well, since you are reading everything as uint8_t AKA unsigned char. In fact, the principle use case for unions is just this sort of "type puning". The whole network layer with it different types of IPv4, IPv6 etc addresses works in a similar way.

Upvotes: 8

AnT stands with Russia
AnT stands with Russia

Reputation: 320531

Don't cast. Use memcpy

char packet[64];
...

assert(sizeof commandTen <= sizeof packet);
memcpy(&commandTen, packet, sizeof commandTen);

This assumes that the sizes and memory layouts match properly (the same assumption a cast-based solution would use).

Upvotes: 1

Related Questions