Reputation: 108
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
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
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 union
s 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
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