A cast should not be performed between a pointer type and an integral type

Viewed 1253

I am performing a pointer assignment in an Embedded C script like so:

uint32_T *a = (uint32_T *) (4096U); 

Basically, I need a to point to the address location 4096 (decimal)

I get the MISRA warning as specified in the title (I use Code Composer Studio's MISRA C:2004 checker).

How can I fix this warning?

PS: uint32_T is a typedef for unsigned long

3 Answers

This is the kind of MISRA-C rule not to take too serious in itself - the rule is advisory and is mostly there to force programmers to think twice and study, before they do something which is potentially dangerous.

There are numerous pitfalls in integer to pointer conversions:

  • Alignment.
  • Different size or representation between pointers and integers.
  • Trap representations, including hardware exceptions and invalid addresses.
  • Type compatibility issues and strict pointer aliasing.

The average programmer is typically not aware of all of the above. And if they aren't, such integer to pointer conversions may be dangerous.

You must know in advance that the address pointed at is valid, and it makes sense to de-reference it with the picked type. For example, if you know that there is a 32-bit hardware register at that memory address, it's perfectly fine to de-reference through a uint32_t* pointer.

You must also know the pointer format for the given system. On 32 bit systems they are typically just 32 bit addresses. On smaller system like 8/16 bit CPUs, you may have different pointer types with sizes between 16 to 24 to 32 bits, making things more complicated.

Summary: if you know what you are doing, you can ignore this advisory MISRA-C rule.


Other issues with your code:

  • Don't use homebrewed integer types, use stdint.h. If you are stuck with C90, then define types with the same name as those in stdint.h and use those.
  • Casting from a memory address to a pointer without using volatile is almost certainly wrong. The compiler doesn't know what's stored there, and may make strange assumptions and incorrect optimizations if you don't volatile-qualify the pointer. And if it's a hardware register or NVM memory, it may change at any time, and must be volatile for that reason too.

Corrected code should be: volatile uint32_t *a = (volatile uint32_t*)4096U;

I work in an environment where casts like that are quite forbidden, for exactly the reasons MISRA pursues.
However in a specific area, this kind of casts is extremely common and follow a specific purpose (namely access to memory-mapped perihperals, especially in environments like embedded microcontrollers).

I have managed to get all relevant parties (superiors, quality engineering, requirement engineering, ...) to agree that the rule is basically applicable and to be obeyed, but that for exactly the special area it is allowed because of being necessary.
I.e. I got a "blanko pass" to ignore these warnings and enjoy the trust to decide when, provided that I document it. Of course this means also to not ignore it in other cases.

So this does not address the question of how to fix it in the code, but it does answer the question of how to avoid trouble because of it in environments where MISRA code checkers are a relevant part of making accepted software.

There is a reasonably good rationale for the Rule - and other than dealing directly with memory mapped registers, it's a very valid Rule.

But MISRA is itself aware that occasionally, Rules need to be violated... which is why we have a deviation process, documented in MISRA Compliance.

In fact, in the specific instance of memory mapped registers, we've even created a permit to aid the deviation. Currently permits only exist for MISRA C:2004 but will be coming for 2012 in due course.

Related