Search code examples
cembeddedbit-manipulationbitwise-operatorsmisra

MISRA C: Type casting and <<, & bit-wise operators error


I've been having a lot of trouble with MISRA when doing << and & operations.

Definitions of types for context

typedef uint32_t uint32;
typedef volatile uint32* canreg_txrx_pointer;
canreg_txrx_pointer canreg_txrx;
uint8_t valueRead, value;
#define CAN_DIR_BIT_POS ((uint8_t)2U)
#define CAN_OUT_BIT_POS ((uint8_t)1U)
#define CAN_IN_BIT_POS ((uint8_t)0U)

When trying to perform a series of << and & operations on the registers, I continually get the error #1397-D (MISRA-C:2004 10.5/R) If the bitwise operators ~ and << are applied to an operand of underlying type unsigned char or unsigned short, the result shall be immediately cast to the underlying type of the operand

An example that doesn't pass the misra check and then an example that does is given below

*canreg_txrx = (uint32)((*canreg_txrx & (~(uint32)(1U << CAN_OUT_BIT_POS))) | (uint32)(value << CAN_OUT_BIT_POS)); //doesn't pass MISRA
valueRead = (uint8_t)(((uint8_t)*regToOperateOn & (uint8_t)(1U << CAN_OUT_BIT_POS)) >> CAN_OUT_BIT_POS); //passes MISRA

I've tried multiple changes to the offending line where none of them have resulted in MISRA letting it through (except randomly where it just gives me no warnings) to the point where I decided to cast everything and that still doesn't work

*canreg_txrx = (uint32)((*canreg_txrx & (uint32)(~(uint32)((uint32)1U << (uint32)CAN_OUT_BIT_POS))) | (uint32)((uint32)value << (uint32)CAN_OUT_BIT_POS)); //doesn't pass MISRA

I'm really confused on how to fix this code so that it will pass MISRA as this bitwise logic is used in multiple places and all of them don't pass. I assumed that if everything is cast to the same type then there should really be no issue since it's all operating at the same type but for some reason that doesn't work.


Solution

  • I have never used Misra but I find your code hard to read with all that noise of typedefs, casts and parenthesis. My suggestion would be to simplify and split the problem into smaller parts along these lines:

    *canreg_txrx = (uint32)((*canreg_txrx & (~(uint32)(1U << CAN_OUT_BIT_POS))) | (uint32)(value << CAN_OUT_BIT_POS)); // =>
    
    *canreg_txrx &= ~(1U << CAN_OUT_BIT_POS);
    *canreg_txrx |= value << CAN_OUT_BIT_POS; // maybe =>
    
    #define BIT_CLEAR(val, pos) ((val) &= ~(1U << (pos)))
    BIT_CLEAR(*canreg_txrx, CAN_OUT_BIT_POS);
    *canreg_txrx |= value << CAN_OUT_BIT_POS; // *
    

    '*' If value is a bit, then this is just bit set, otherwise can't think of good name.

    Then run it through Misra and only fix what it complains about.