Search code examples
cmisrainteger-promotion

Misra Rule violation "composite expression shall not be assigned to an object with wider essential type" and Integral promotion


I have below function to check some count value and update the final count.

uint16 final_count = 0U;

uint8 count1 = 0U;
uint8 count2 = 0U;
uint8 count3 = 0U;
uint8 count4 = 0U;
  
void test(void)
{
  uint8 input = 0U;

  input =  get_input(); //Input
  count1 = get_count1(); //count1
  count2 = get_count2(); //count2
  count3 = get_count3(); //count3
  count4 = get_count4(); //count4
  
  if(input == 1U)
  {
      final_count= count1 + count2; // Both warnings Here
  }
  else if(input == 2U)
  {
      final_count= count2 + count3; // Both warnings Here
  }
  else
  {
     final_count= count1 + count2 + count3 + count4; // Both warnings Here
  }
}

During the MISRA check, I am getting below errors in the if else

  1. A composite expression of 'essentially unsigned' type (unsigned char) is being converted to wider unsigned type, 'unsigned short' on assignment.
  2. Integral promotion : unsigned char promoted to signed int.

I have tried to solve by below method

final_count = (uint16)(count1 + count2);
final_count = (uint16)(count3 + count4);
final_count = (uint16)(count1 + count2 + count3 + count4);

But this couldn't able to solve above MISRA warnings. What is the exact problem happening here? Any suggestion to solve these warnings with out temporary variables?


Solution

  • Composite expression is a term defined by MISRA C and refers to arithmetic or bitwise operators inside sub-expressions (MISRA C:2012 8.10.3). (Not to be confused with the ISO C term composite type.)

    In your case count1 + count2 is a composite expression. The operands are uint8_t and therefore essentially unsigned. You assign this to a wider unsigned type uint16_t and therefore the code violates rule 10.6.

    MISRA gives two rationales for this "composite expression" rule 10.6:

    • Programmers may not be aware that both operands are getting implicitly promoted to int which is signed.
    • Some confused programmers might have the misconception that just because the result of the expression is stored in a uint16_t then the addition is also carried out using uint16_t which is of course wrong. (MISRA seems rather hellbent on insisting that this is a common misconception, but I'm not really convinced...)

    Furthermore rule 10.8 says that we aren't allowed to cast the result of a composite expression to a wider essential type (the (uint16_t) cast versions). Here the intention is to prevent hidden surprises such as overflows and wrap-arounds. For example in your specific case it isn't clear if you expect a 8 bit wrap-around at 255 to happen or if you expect the result to take larger values than 255. Nobody (including yourself years from now) can tell just by watching the uncommented code. So casting the result won't work either.

    The solution is to cast the variables to the intended type before doing the addition:

     final_count = (uint16_t)count1 + (uint16_t)count2;
    

    As a side-note, please make it a habit to use standard C types uint8_t and not some private garage non-standard uint8/u8/byte... Good engineering = following standards and best practices. Bad engineering = complicating things just for the heck of it.