#define HNULL (void*)0
BYTE *VRAM_OPTION_I_BIT = HNULL;
WORD *VRAM_OPTION_I_WORD = HNULL;
void Func1(void)
{
VRAM_OPTION_I_BIT = (BYTE *)(PLC_Data + VRAM_OPTION_I_BIT_ADDR);
VRAM_OPTION_I_WORD = (WORD *)VRAM_OPTION_I_BIT; // MISRA Violation 11.3
}
The above code gives a MISRA violation. MISRA C:2012 Rule 11.3 A cast shall not be performed between a pointer to object type and a pointer to a different object type
A common method that I found to solve it was to change the data type of VRAM_OPTION_I_WORD and VRAM_OPTION_I_BIT to void*.
However, the code gives compilation issues when run in the hardware. Is there a feasible method to solve it ?
The main concern here is that it isn't well-defined to access a byte array through a word pointer in C. Alignment and strict pointer aliasing being the reasons why, that's a FAQ and you can read about it here What is the strict aliasing rule?
Now strict aliasing is mostly just an annoying "defect" in C when it comes to embedded systems and hard-ware related programming, but we can't ignore it, especially not in safety-related software. With a gcc-like compiler it is strongly recommended to disable all strict aliasing optimizations with -fno-strict-aliasing
. That will remove the hazard but still not sate MISRA C and the code will not be portable either.
Given that a byte in your setting corresponds to a character type, it is actually safe to access any data type through such a pointer, but that's a very special case and does not apply to larger object pointer types.
Avoid using void*
in high integrity embedded systems - there should ideally be no unknown types or type-generic programming in such a system. So it's not a solution but another problem.
The general work-around is as follows:
PLC_Data
is some integer, then you can do an integer-to-pointer conversion as:(WORD *)(PLC_Data + VRAM_OPTION_I_BIT_ADDR)
. This will put you up against another MISRA rule 11.4, but that one is advisory and far less severe than 11.3.Unrelated to your question, common best practices in C are as follows:
Do not invent home-brewed type systems. Good engineering == following existing standards. In this case you should be using standard uint8_t
and uint16_t
etc from stdint.h
. Not invent some home-made BYTE
/WORD
etc - all you achieve with that is making the code harder to read and more error prone.
Declaring variable names in ALL CAPS is not a common style. All caps is typically used for macros and constants, and in case of embedded systems, often also for hardware registers. Do not use it for non-const variable names or types.
Declaring variables outside any function at file scope ("globals") is bad practice and has been debated endlessly elsewhere. And naturally it is not allowed in MISRA C either for those well-known reasons. You have to move the variables inside a function or declare them as static
.