How to cast a struct onto a different struct member - c

How can I have a variable point to a member of a different struct? This is what I'm trying to do, but the third line fails.
volatile uint8_t tx_message_buffer[sizeof(MESSAGE)];
struct MESSAGE *tx_message = (MESSAGE *)tx_message_buffer;
struct PAYLOAD *tx_payload = (PAYLOAD *)tx_message->payload;
Here are the struct definitions.
#define MSG_MAX_PAYLOAD_LENGTH 64
typedef struct PAYLOAD {
uint8_t descriptor;
uint8_t parameters[MSG_MAX_PAYLOAD_LENGTH-1];
};
typedef struct MESSAGE {
uint8_t address;
uint8_t length;
PAYLOAD payload;
uint8_t checksum;
};

This code has many problems.
As pointed out in other answers, you cannot set a pointer to point at a PAYLOAD payload; member, you need to point at its address, &tx_message->payload.
typedef struct PAYLOAD {} should be typedef struct {} PAYLOAD.
(MESSAGE *)tx_message_buffer is a completely wild cast, which invokes several cases of poorly defined behavior. First of all, you should never cast away volatile qualifiers. But also, as soon as you de-reference this struct you will violate strict aliasing and invoke undefined behavior. Anything can happen.
To solve these pointer bugs, you can do something similar to this:
typedef struct {
uint8_t address;
uint8_t length;
PAYLOAD payload;
uint8_t checksum;
} MESSAGE;
typedef union {
MESSAGE message;
uint8_t tx_message_buffer[sizeof(MESSAGE)];
} message_something;
This code is valid and well-defined.
Using a struct to represent a data protocol is bad practice, as you must ensure that the struct contains no padding at all. The memory layout in your MESSAGE struct is by no means guaranteed to correspond to the memory layout of the data protocol. The struct may have padding bytes to suit the alignment requirements of the specific CPU.
Disabling padding with non-standard C such as #pragma pack(1) may or may not be sufficient, depending on your portability requirements. To achieve full portability, you may have to write serialization/deserialization routines.

You have a bigger issue in your code: the cast on the second line is not valid, because the storage for struct MESSAGE may generally have different alignment requirements than char[] array. For example, changing the type of descriptor to uint32_t could force an even-address location for the entire struct on some platforms.
Doing it the other way around would be valid, through, because you are allowed to convert any object pointer to char *:
volatile struct MESSAGE tx_message;
volatile uint8_t *tx_message_buffer = (char*)tx_message;
The third line fails because you did not take a pointer of PAYLOAD struct:
struct PAYLOAD tx_payload = &tx_message.payload;
There is no need to cast the result, because tx_message.payload is already of the correct type.

By using,
PAYLOAD payload;
You are getting a variable not a pointer. Meaning that
message->payload;
Is not a pointer.
You need to use a pointer.
PAYLOAD * payload;
Or get the address of the struct
&message->payload;

Related

Pointer to Union of Structs

I'm working with an USART device that send to my MCU a series of different commands (also different is size) and I want to try the best way to parse the commands.
I defined two packed structure (one for each command)
typedef ccport_PACKED( struct TASK_CommandStandard
{
UINT8 startByte;
UINT16 length;
UINT8 command;
UINT16 crc16;
}) TASK_CommandStandard_t;
typedef ccport_PACKED( struct TASK_CommandExitBootloader
{
UINT8 startByte;
UINT16 length;
UINT8 command;
UINT8 reserved;
UINT16 crc16;
}) TASK_CommandExitBootloader_t;
and one Union:
typedef union TASK_Command
{
TASK_CommandStandard_t standard;
TASK_CommandExitBootloader_t exitbootloader;
} TASK_Command_t;
My application receives the USART command inside a UINT8 buffer and after that, looking into the 4th byte I can detect the type of the command (standard or exitbootloader).
To parse the command, my idea is to use one pointer TASK_Command_t *newCommand and based on the command code, assign the address of instance.rxFrameBuffer to:
newCommand->exitbootloader = (TASK_CommandExitBootloader_t *)instance.rxFrameBuffer
or
newCommand->standard = (TASK_CommandStandard_t *)instance.rxFrameBuffer
This is my function:
static void TASK_FSM_FrameReceived( void )
{
UINT8 commandCode;
TASK_Command_t *newCommand;
commandCode = instance.rxFrameBuffer[TASK_COMMAND_CODE_INDEX];
if( commandCode == TASK_COMMAND_CODE_EXIT_BOOTLOADER )
{
newCommand->exitbootloader = (TASK_CommandExitBootloader_t *)instance.rxFrameBuffer;
}
else
{
newCommand->standard = (TASK_CommandStandard_t *)instance.rxFrameBuffer;
}
......
}
Unfortunately, the compiler returns this error:
incompatible types when assigning to type 'TASK_CommandExitBootloader_t' {aka 'struct TASK_CommandExitBootloader'} from type 'TASK_CommandExitBootloader_t *' {aka 'struct TASK_CommandExitBootloader *'}
Can someone give me a hint?
newCommand->exitbootloader isn't a pointer, it's a struct, thus if you want to copy data of instance.rxFrameBuffer to this struct, you need to use memcpy, or union. You could also dereference like so *((TASK_CommandExitBootloader_t *)instance.rxFrameBuffer) however this may be undefined behaviour depending the type of rxFrameBuffer, so I don't recommend it.
newCommand is an uninitialized pointer so it can't be used until you point at valid memory somewhere. The code will crash & burn when you attempt newCommand->exitbootloader.
You can't just wildly point into an UART rx buffer and merrily be on your way. Where is this data coming from, interrupts or DMA? How do you handle re-entrancy? Where are the actual volatile qualifier registers and how did you get the data from there?
Strict aliasing is real and it is nasty, particularly if using gcc. So you can't point into a pre-declared uint8_t array buffer for that reason. You can cast between those two different struct types if the union containing them both is present, but better to avoid all such conversions.
I'd also strongly recommend dropping "my local garage standard" types UINT8 or whatever in favour for internationally standardized, well-known C standard types uint8_t etc from stdint.h.
Also regarding hard copy of raw UART buffers on low-end microcontroller systems, that's a very common beginner mistake. See this answer for an example of how to do it properly.
I had to do something similar (pointer to raw data to save memory)
I did something like this :
typedef struct TASK_CommandStandard
{
volatile UINT8 startByte;
volatile UINT16 length;
volatile UINT8 command;
volatile UINT16 crc16;
} TASK_CommandStandard_t;
typedef struct TASK_CommandExitBootloader
{
volatile UINT8 startByte;
volatile UINT16 length;
volatile UINT8 command;
volatile UINT8 reserved;
volatile UINT16 crc16;
} TASK_CommandExitBootloader_t;
#define USART_Foo_Address 0x0F00000
#define USART_cmd ((TASK_CommandStandard_t*) USART_Foo_Address)
#define USART_exit ((TASK_CommandExitBootloader_t*) USART_Foo_Address)
Don't forget to check padding/alignment, it was working fine on my MCU
You use it like this :
static void TASK_FSM_FrameReceived( void )
{
if( instance.rxFrameBuffer[TASK_COMMAND_CODE_INDEX] == TASK_COMMAND_CODE_EXIT_BOOTLOADER )
{
USART_exit->length;
....
}
else
{
USART_cmd->length;
....
}
......
}
I solved modifing the union:
typedef union TASK_Command
{
TASK_CommandStandard_t *standard;
TASK_CommandExitBootloader_t *exitbootloader;
} TASK_Command_t;
and in my function insted using a
TASK_Command_t *newCommand;
I used
TASK_Command_t newCommand;
In this way I can use the same variable to cast my different messages without make any buffer copy.
I can access to the UART buffer with
newCommand.standard = (TASK_CommandStandard_t *)instance.rxFrameBuffer;

Why is this struct type "incomplete," and is it really solved with a pointer?

I have defined these structures.
struct http_req {
struct http_req_line rl;
}
struct http_req_line {
enum method {
OPTIONS,
GET,
HEAD,
POST,
PUT,
DELETE,
TRACE,
CONNECT
} method;
enum uri_type {
ASTERISK,
ABSOLUTEURI,
ABS_PATH,
AUTHORITY
} uri_type;
union req_uri {
char asterisk[1];
char absoluteURI[256];
char abs_path[256];
char authority[256];
} req_uri;
char http_ver[16];
};
When I compile the file this header file is included in (which compiles fine on its own), gcc gives me this
request_types.h:2:23: error: field ‘rl’ has incomplete type
struct http_req_line rl;
But changing the 2nd line of the header to
struct http_req_line *rl;
gets rid of this error. What causes this error, and does changing that member to a pointer really fix the problem, or just hide it from the compiler?
At the point where the compiler sees:
struct http_req {
struct http_req_line rl;
}
there is no information about what a struct http_req_line is. You need the structure definition for struct http_req to appear after the definition of struct http_req_line. You can use a pointer (to an incomplete type); you can't use a copy of the structure.
See the C11 standard §6.7.2.1 Structure and union specifiers:
A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), …
At the point where you are defining struct http_req, struct http_req_line is not known. The compiler does not know how big it is or what its alignment requirement is, so it does not know how much space to use for the rl member and cannot complete its definition of struct http_req.
If you want to embed a struct http_req_line inside a struct http_req, move the definition of struct http_req_line before the definition of struct http_req.
If you change rl to be a pointer, the type is not incomplete in the C sense because the compiler will know how big the pointer is and what its alignment requirement is. It does not need to know how big the structure it points to is in order to be able to plan space for the pointer rl.
You're seeing this error because you're attempting to define an instance of a struct before the struct itself has been defined. You need to define it first, then use it:
struct http_req_line {
enum method {
OPTIONS,
GET,
HEAD,
POST,
PUT,
DELETE,
TRACE,
CONNECT
} method;
enum uri_type {
ASTERISK,
ABSOLUTEURI,
ABS_PATH,
AUTHORITY
} uri_type;
union req_uri {
char asterisk[1];
char absoluteURI[256];
char abs_path[256];
char authority[256];
} req_uri;
char http_ver[16];
};
struct http_req {
struct http_req_line rl;
};
The reason that changing the member type to a pointer works is because you don't need to have the full struct definition to use a pointer to it. When the type definition is needed is when that pointer would be dereferenced.

How to union an array pointer?

I have the following struct definition:
typedef struct mb32_packet_t {
union {
struct {
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
};
uint8_t header[9];
};
uint8_t *payload;
uint16_t checksum;
} __attribute__((packed)) mb32_packet_t;
Now I would like to have another union, so that I can get an uint8_t body[] pointer to the entire packet object. Something like this:
typedef struct mb32_packet_t {
union {
struct {
union {
struct {
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
};
uint8_t header[9];
};
uint8_t *payload;
uint16_t checksum;
};
uint8_t body[?];
};
} __attribute__((packed)) mb32_packet_t;
The problem is that the payload field size is dynamically determined at runtime. Is there another way to accomplish this other than making payload fixed sized?
I basically want to send objects of this type through a network socket, so I need a uint8_t pointer that points to an object of this type. At the time of sending the object, I know the size of the entire object in bytes.
Introduction
The question is unclear, so I will discuss three apparent possibilities.
Fixed-length header followed by variable-length payload
A typical way to define a packet for a networking or messaging service is to have a fixed-length header followed by a variable-length payload. In modern C, the variable-length payload may be defined using a flexible array member, which is an array with no dimension at the end of a structure:
typedef struct
{
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
uint8_t payload[];
} mb32_packet_t;
Memory for such a structure is allocated use the base size provided by sizeof plus additional memory for the payload:
mb32_packet_t *MyPacket = malloc(sizeof *MyPacket + PayloadLength);
When you pass such an object to a routine that requires a char * or uint8_t * or similar type for its argument, you can simply convert the pointer:
SendMyMessage(…, (uint8_t *) MyPacket,…);
That cast, (uint8_t *) MyPacket, provides the pointer to the first byte of the packet requested in the question. There is no need to wedge another member into the structure or layer on a union or other declaration.
Prior to the introduction of flexible array members in C 1999, people would use one of two workarounds to create structures with variable amounts of data. One, they might just define a member array with one element and adjust the space calculations accordingly:
typedef struct
{
…
unsigned char payload[1];
} mb32_packet_t;
mb32_packet_t *MyPacket = malloc(sizeof *MyPacket + PayloadLength - 1);
Technically, that violated the C standard, since the structure contained an array of only one element even though more space was allocated for it. However, compilers were not as aggressive in their analysis of program semantics and their optimization as they are now, so it generally worked. So you may still see old code using that method.
Two, GCC had its own pre-standard implementation of flexible array members, just using an array dimension of zero instead of omitting a dimension:
typedef struct
{
…
unsigned char payload[0];
} mb32_packet_t;
Again, you may see old code using that, but new code should use the standard flexible array member.
Fixed-length header with pointer to variable-length payload
The payload-after-header form shown above is the form of packet I would most expect in a messaging packet, because it matches what the hardware has to put “on the wire” when sending bytes across a network: It writes the header bytes followed by the data bytes. So it is convenient to have them arranged that way in memory.
However, your code shows another option: The data is not in the packet but is pointed to by a pointer in the packet, with uint8_t *payload;. I would suspect that is a mistake, that the network or messaging service really wants a flexible array member, but you show it followed by another member, uint16_t checksum. A flexible array member must be the last member in a structure, so the fact that there is another member after the payload suggests this definition with a pointer may be correct for the messaging service you are working with.
However, if that is the case, it is not possible to get a pointer to the complete packet object, because the object is in two pieces. One contains the header, and the other, at some unrelated location in memory, contains the data.
As above, you can produce a uint8_t * pointer to the start of the packet with (uint8_t) MyPacket. If the messaging system knows about the pointer in the structure, that should work. If you have mistaken what the packet structure must be, it will fail.
Fixed-length header followed by fixed-length payload space
Code elsewhere on Stack Overflow shows a struct mb32_packet_t with a fixed amount of space for a payload:
typedef struct mb32_packet_t {
uint8_t compid;
uint8_t servid;
uint8_t payload[248];
uint8_t checksum;
} __attribute__((packed)) mb32_packet_s;
In this form, the packet is always a fixed size, although the amount of space used for the payload could vary. Again, you would obtain a uint8_t * pointer to the packet by a cast. There is no need for a special member for that.
This is possible, but not with a struct or union, because all parts of a struct or union need to have a known size. You can still use a struct for the header.
Because the body starts at a known location, there's a trick you can use to access it as if it was part of the structure. You can declare it with no size at all (a "flexible array member") or as 0 bytes (a GCC extension that predates the standard). The compiler will not allocate any space for it, but it will still let you use the name to refer to the end of the struct. The trick is that you can malloc extra bytes after the end of the struct, and then use body to refer to them.
typedef struct mb32_packet_t {
union {
struct {
uint16_t preamble;
uint8_t system_id;
uint8_t message_id;
uint8_t reserved;
uint32_t paylen;
};
uint8_t header[9];
};
uint8_t body[]; // flexible array member
} __attribute__((packed)) mb32_packet_t;
// This is not valid. The body is 0 bytes long, so the write is out of bounds.
mb32_packet_t my_packet;
my_packet.body[0] = 1;
// This is valid though!
mb32_packet_t *my_packet2 = malloc(sizeof(*my_packet2) + 50);
my_packet2->body[49] = 1;
// Alternative way to calculate size
mb32_packet_t *my_packet3 = malloc(offsetof(mb32_packet_t, body[50]));
my_packet3->body[49] = 1;
The flexible array member must be last. To access the checksum, you will need to allocate an extra 2 bytes, and use pointer arithmetic. Fortunately, this is just for the checksum, and not the entire header.
mb32_packet_t *my_packet = malloc(sizeof(*my_packet) + body_size + 2);
uint16_t *pchecksum = (uint16_t*)&my_packet.body[body_size];
// or
uint16_t *pchecksum = (uint16_t*)(my_packet.body + body_size);
After you fill in the header, body and checksum, then because they are contiguous in memory, a pointer to the header is also a pointer to the entire packet object.
I usually do it this way:
typedef struct
{
size_t payload_size;
double x;
char y[45];
/* another members */
unsigned char payload[];
}my_packet_t;
or if your compiler does not support FAMs
typedef struct
{
size_t payload_size;
double x;
char y[45];
/* another members */
unsigned char payload[0];
}my_packet_t;
So it the payload can be at the end of the header structure

Opaque structure with flexible array member

Suppose I have a struct declaration in a header file like:
event.h
struct event_t;
and in the corresponding C file I would like to sort-of alias it with the Linux-specific struct inotify_event. The problem is that struct inotify_event contains flexible array member:
struct inotify_event {
int wd;
uint32_t mask;
uint32_t cookie;
uint32_t len;
char name[];
};
As per 6.7.2.1(p3) (emphasize mine):
A structure or union shall not contain a member with incomplete or
function type (hence, a structure shall not contain an instance of
itself, but may contain a pointer to an instance of itself), except
that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union
containing, possibly recursively, a member that is such a structure)
shall not be a member of a structure or an element of an array.
it is not possible to define the struct event_t as
struct event_t{
struct inotify_event base; //Non-conforming
};
So I could convert struct event_t * to struct inotify_event *. Since the 6.7.2.1(p3) concerns only about structs the solution I see is to redeclare the tag name as
union event_t
and then define it later as a single element union.
union event_t{
struct inotify_event event; //Conforming?
};
The only requirement the Standard imposes on union that I found is that the set of members of a union must be non-empty 6.2.5(p20) (emphasize mine):
A union type describes an overlapping nonempty set of member objects,
each of which has an optionally specified name and possibly distinct
type.
QUESTION: Is it a conforming/common way to hide an implementation details of some specific data structure through union?
This is how I would do it:
event.h
struct event_t;
event_t *create_event(void);
void free_event(event_t *ev);
event.c
#include "event.h";
event_t *create_event(void)
{
inotify_event *iev = ...;
return (event_t *)iev;
}
void free_event(event_t *ev)
{
inotify_event *iev = (inotify_event *)ev;
// free the event
}
However, if you want to store additional data with the event then:
event.h
struct event_t;
event_t *create_event(void);
void free_event(event_t *ev);
event.c
#include "event.h";
struct event_t
{
inotify_event *iev;
// additional data
};
event_t *create_event(void)
{
inotify_event *iev = ...;
event_t *ev = malloc(sizeof(event_t));
ev.iev = iev;
return ev;
}
void free_event(event_t *ev)
{
inotify_event *iev = (inotify_event *)ev.iev;
// free the event (iev) first
free(ev);
}
If you have multiple implementations that you need to hide in event_t then:
enum event_type
{
EVENT_TYPE_INOTIFY,
EVENT_TYPE_INOTIFY2,
};
struct event_t
{
event_type type;
union {
inotify_event *iev; // you use this when type == EVENT_TYPE_INOTIFY
inotify_event2 *iev2; // you use this when type == EVENT_TYPE_INOTIFY2
}
// additional data
};
By far the simplest technique is to put this into your event.h header:
typedef struct inotify_event event_t;
This declares that there is a structure type struct inotify_event and declares an alias for it event_t. But it does not define the content of struct inotify_event at all.
Only the implementation code in event.c includes the definition of struct inotify_event from the system header; everything else does not include that header and cannot access the elements of an event_t except through the accessor API you define.
You can enforce this separation of duties by code review — or by checking with grep, or other similar techniques — to ensure that no code except the implementation of your event type uses the system header for inotify_event. And, if you port to a system other than Linux without support for inotify, then you simply provide an alternative opaque structure type in place of struct inotify_event in your event.h header.
This avoids all questions about whether there are flexible array members within structures, etc; it is all a non-issue.
Note the Q&A about What does a type followed by _t (underscore t) represent? . Be cautious about creating your own types with the _t suffix ¸— consider using a prefix on such type names that gives you a chance that your names will be distinct from those provided by the system.
Single element union makes no sense. The purpose of union is to serve as a kind of polymorphic struct. struct members are accessed by offset, this is why is impossible to put an incomplete struct or array in the middle of a struct.
For example
struct foo { int a; int b[]; int c; };
In this example is impossible for the compiler to determine the address of c because b size can vary at runtime. But if you put incomplete array at the end all struct members address can be determined by the address of the start of the struct. Keep in mind that pointers are just address, so you can have any pointers to any structs and all the offsets can be determined, but you will need to deal with extra alloc/free stuff.
When you create an union you telling to compiler Hey! I have this members, reserve enough space for me so that I can treat this variable as foo or bar. In another words, the compiler will take the largest union member and this will be the size of the union. A common use for union is for representing multiple kinds of values.
typedef union { int integer, float real, char *string } value_type;
This way you can treat value_type as int, float, or a char pointer. You're code need to know the how to treat each member but the compiler will make sure that when you do malloc(sizeof value_type) you have enough space for the tree types.
Now your problem. You want to hide implementation details. Usually this is done by declaring a type or struct incompletely in a header, and completely only on your object files. Because of this when the user include your header all the information that the compiler has is struct my_struct;. It can't tell the size of my_struct so is impossible for you to allocate it as malloc(sizeof struct my_struct). Also since the user hasn't the member definitions it can't mess up with the struct internals.
Working like this you will need to provide user with functions for allocating and freeing my_struct, for example struct my_struct *foo = my_struct_new() and my_struct_destroy(foo).
You're already doing this. To deal with the struct inotify problem I would do one of these.
(1) Surround OS specific with #ifdef for that OS, so that the event_t has only the right members defined depending on the operating system. You will need #ifdef on your functions. This has the advantage to keep useless code out of final binary, so smaller footprint.
(2) Have pointers to OS specific structs and let runtime decide what to do. This easier to maintain.

polymorphism in c and buffers

I have this union:
typedef union Message
{
message_base base;
message_with_parameters parameters;
reply_message reply;
buffer_t *buffer; // can't figure out what to put here
} message;
message_with_parameters has a message_base as the first field and reply_message has a message_with_parameters as as the first field which in turns has message_base as as the first field.
So basically I can access any of them and I'll still get all the data I need, however I am getting a buffer from my driver and now I want to serialize it into the message.
I already know that the pointer to the buffer is wrong as it won't correlate with my structs but I can't have a fixed size buffer.
Somewhere along the way I want to do this:
m->buffer = buff->payload;
And no matter what kind of data type I have, it will still serialize.
How can it be done?
EDIT:
Here are my structs:
typedef struct MessageBase
{
uint32_t u32DeviceID;
uint32_t u32CoreID;
uint16_t u16Class;
uint16_t u16CRC;
uint8_t u8OpCode;
void (*states [MAX_OPCODES]) (void *);
} message_base;
typedef struct MessageWithParameters
{
message_base base_class;
uint8_t u8Param1;
uint8_t u8Param2;
} message_with_parameters;
typedef message_with_parameters reply_message;
typedef union Message
{
message_base base;
message_with_parameters parameters;
reply_message reply;
} message;
its because the data in the buffer isn't part of the union.
buffer_t* buffer is a pointer, so the pointer is part of the union, not the data which it points at
you probablly want to do something like
m = (message*) buff->payload;

Resources