Reputation: 21
I'm trying to convert a certain pointer as follows:
I have this struct:
typedef struct {
/** Interface index */
uint8_t if_index;
/** flags */
uint32_t flags; /* error */
/** packet id */
uint32_t packet_id;
/** structure must be aligned to 32 bit */
uint8_t padding[3];
} v2x_tx_indication_value_t;
and trying to perform this conversion:
lmac_cv2x_tx_packet_id_t *packet_id_ptr = NULL;
packet_id_ptr = (lmac_cv2x_tx_packet_id_t *)&tx_ind_ptr->packet_id;
This conversion is not MISRA compliant (according to rule 11.3) since the data is not aligned properly. I tried to align the address according to this following solution but it compile (Error: "expression must have integral typeC/C++(31)"):
if ((address & 0x3) == 0) {
packet_id_ptr = (lmac_cv2x_tx_packet_id_t *)&tx_ind_ptr->packet_id;
}
Could use some help if anyone has any better ideas here :)
Upvotes: 0
Views: 602
Reputation: 1301
As noted before, alignment is just a part of Rule 11.3 rationale. Indeed, it's about (prohibiting of) type punning.
As far as I understand, there is no way to do what you need if all MISRA rules are enabled. But if the code in question is for communication tasks where there are many different packet formats, flexible header etc., it is very likely that Rule 11.5 ("A conversion should not be performed from pointer to void into pointer to object") is already disabled.
If so, one can use:
lmac_cv2x_tx_packet_id_t *packet_id_ptr = NULL;
packet_id_ptr = (lmac_cv2x_tx_packet_id_t *)(void*)&tx_ind_ptr->packet_id;
(Note that rules 11.3 and 11.4 uses "between ... and ...", and rule 11.5 uses "from ... to ...")
If it is possible, I prefer to use transitional void * pointers (as function parameters or local variables) to avoid cascaded casts and make code more readable.
Upvotes: 0
Reputation: 213711
You simply cannot do wild pointer conversions like this in C. Alignment isn't the only issue, but also strict pointer aliasing and portability.
Regarding alignment/padding, adding uint8_t padding[3];
at the end achieves nothing - if there was need for padding there, the compiler would have added it automatically.
You need to rewrite the code. This is one option:
typedef union
{
lmac_cv2x_tx_packet_id_t stuff;
uint32_t packet_id;
} packet_id_t;
typedef struct {
/** Interface index */
uint8_t if_index;
/** flags */
uint32_t flags; /* error */
/** packet id */
packet_id_t packet;
} v2x_tx_indication_value_t;
Unfortunately union
is problematic with other MISRA-C rules but in this case you are using it for type punning rather than for storing unrelated data in the same memory location, which is what MISRA-C forbids with the union
rule, so deviations are possible and sensible.
Using C11 anonymous union should be fine too far as I can tell from MISRA-C:2012 amendment 2. It might confuse your static analyser though, in case it doesn't support C11. Example:
typedef struct {
/** Interface index */
uint8_t if_index;
/** flags */
uint32_t flags; /* error */
/** packet id */
union // C11 anonymous union
{
lmac_cv2x_tx_packet_id_t stuff;
uint32_t packet_id;
};
} v2x_tx_indication_value_t;
Another option is memcpy
.
Upvotes: 1