0

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?

user2986042
  • 1,098
  • 2
  • 16
  • 37

2 Answers2

3

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • @Ludin If we cast explicitly, we can solve R.10.6 problems. But Still I am getting R.10.8 warning ( Integral promotion : unsigned char promoted to signed int. ) . Any idea how to solve this issue? – user2986042 Apr 06 '23 at 11:27
  • @user2986042 My posted example is MISRA compliant. There is no composite expression getting cast so rule 10.8 does not apply. Perhaps post a separate follow-up question with your modified code? Include info regarding which static analyzer that was used. – Lundin Apr 06 '23 at 11:35
1

In your example, you are declaring (with my annotation):

uint16 final_count = 0U;   // uint16

uint8 count1 = 0U;         // uint8
uint8 count2 = 0U;         // uint8
uint8 count3 = 0U;         // uint8
uint8 count4 = 0U;         // uint8

Your three assignments are:

final_count= count1 + count2;                    // uint16 = uint8 + uint8
final_count= count2 + count3;                    // uint16 = uint8 + uint8
final_count= count1 + count2 + count3 + count4;  // uint16 = uint8 + uint8 + uint8 + uint8

This violates MISRA C:2012 R.10.6 and R.10.8

You then ask:

What is the exact problem happening here? Any suggestion to solve these warnings

An explanation can be found in s8.10.3 and Appendix C of MISRA C:2012 - you have read the book, haven't you, and are not just relying on a tool's output?

The problem here is a (very common) misunderstanding of the strange (but well defined) integer promotion behaviours that C exhibits, especially when using unsigned integers smaller than int (which get promoted to signed int when you might not expect) - as highlighted by your Error 2.

There is also the real risk that four uint8 may overflow. eg

uint16 = uint8 + uint8;      // performed in uint8
                             // then converted to uint16

Adding the cast may solve the R.10.6 problems, but not your R.10.8 issues.

In your example, the simplest solution would be to declare your four countn variables as uint16 then all the calculations are performed in uint16, while the assignments would not be composite expressions and so the implicit conversion is OK.

(see profile for MISRA affiliation)

Andrew
  • 2,046
  • 1
  • 24
  • 37