MISRA Discussion Forums

Full Version: Circular logic with rule 12.1
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello,

I had a violation for rule 10-5 (the result of a
Just a heads up, I am able to fix it with:

[code]BurnCount = (ushort16)(EEPROM_BANK0[1]) + (ushort16)((ushort16)(EEPROM_BANK0[0])
Rule 12.1 deals mainly with operator precedence. For example, the following are exactly equivalent but the rule advises using the second form because it makes the intent absolutely clear:
Code:
a + (b * c)
a + b * c

However, it also mentions associativity of operators in its rationale and suggests using parentheses to control the order in which operations occur. In my opinion, it isn't helpful for Rule 12.1 to try and deal with associativity because Rule 10.1 does a better job of catching those instances where it matters. However, the 2004 rules are superseded by the 2012 ones so I don't think they will be receiving any further technical updates.

The problem with associativity is that in algebra, addition is associative, e.g.
Code:
a + (b + c) == (a + b) + c
but in C it's not necessarily the case. If a, b and c are all unsigned integer types and are either (a) all the same size, or (b) no wider than the int type, then addition is associative. But if they are different unsigned integer types with one wider than int then you can't guarantee that the result is independent of the order of operation. If they are signed types or floating-point types then you also can't guarantee associativity because of the possibility of overflows.

For example, suppose:
Code:
unsigned int a = 1u;
unsigned int b = 65535u;
unsigned long c = 1u;

Consider the expression (a + b) + c on a machine in which int is 16 bits wide and long is 32 bits wide. The rules of C say that the program must behave as if the addition in (a + b) is performed first and then c is added. So, (a + b) is evaluated in the unsigned int type giving 65536. But 65536 doesn't fit in unsigned int so according to the rules of unsigned types in C it's reduced modulo 65536 giving 0. The value is then widened to 32 bits and added to c giving a result with value 1 and type unsigned long.

On the other hand the expression a + (b + c) on is evaluated as if the addition in (b + c) is performed first and then a is added. So, according to the C rules, b is first widened to 32 bits and added to c giving 65536 which happily fits in 32 bits. Then a is widened to 32 bits and added to 65536, giving a result with value 65537 and type unsigned long. So, addition isn't necessarily associative in C.

There are a few other points to note:
  • The order in which the operands a, b and c are evaluated is independent of the order in which the addition operations occur;
  • An implementation only has to behave as if the rules of C are being obeyed; if the compiler is able to determine that the result cannot be affected by the order of operations then it is free to choose a different order.

I believe that your tool is flagging a violation of Rule 12.1 because you have mixed types, i.e.:
Code:
ushort16 + ushort16 + unsigned int

You might find that casting your 1u to ushort16 type fixes the problem. But I'd say that you don't have a real issue here anyway because all your types are no wider than unsigned int so the result can't be affected by the order of operation. If it were a problem then I'd expect Rule 10.1 to be flagged as would be the case if you changed your constant from 1u to 1uL for example.

That's all a bit complicated but I hope it helps.
Interesting, you hit it right on the head with the different data types. I changed it to:

Bur[code]nCount = (ushort16)(EEPROM_BANK0[1]) + (ushort16)((ushort16)(EEPROM_BANK0[0])
The initial example had the underlying types of "( unsigned short + unsigned short ) + unsigned char". This does not violate rule 10.1 or any other MISRA-C:2004 type checking rule. There is also no violation of rule 12.1.