Circular logic with rule 12.1

6.12 Expressions

Moderators: misra-c, david ward

Post Reply
jbrookley
Posts: 12
Joined: Thu Aug 08, 2013 5:56 pm
Company: Kavlico

Circular logic with rule 12.1

Post by jbrookley » Mon Oct 28, 2013 10:30 pm

Hello,

I had a violation for rule 10-5 (the result of a<<b should be cast to the ushort16 type) with the following line:

Code: Select all

BurnCount = ((ushort16)(EEPROM_BANK0[1]) + ((ushort16)(EEPROM_BANK0[0]) << 8u)) + 1u;
No big deal, I added in an additional conversion, which I thought should fix the problem (and it did). However, it added a new rule I've never seen before (in my code anyway), rule 12.1, which stated "Change the order of integer operations from (a+b)+c to a+(b+c)". The line of code that got the offending error was:

Code: Select all

BurnCount = ((ushort16)(EEPROM_BANK0[1]) + (ushort16)((ushort16)(EEPROM_BANK0[0]) << 8u)) + 1u;
Once again, I figured, no big deal, and changed the order to:

Code: Select all

BurnCount = 1u + ((ushort16)(EEPROM_BANK0[1]) + (ushort16)((ushort16)(EEPROM_BANK0[0]) << 8u));
Unfortunately, my code is now telling me "Change the order of integer operations from a+(b+c) to (a+b)+c".

So I'm not sure what is going on at this point. Realistically, it could be an issue with the software I'm using to evaluate this (Parasoft C++ Test) but thus far, everything it's flagged has been consistent with MISRA C requirements.

Can anyone explain this to me? I ordered the official MISRA C compliance rules but they're not due to arrive for a few more days . . .

Thanks!

jbrookley
Posts: 12
Joined: Thu Aug 08, 2013 5:56 pm
Company: Kavlico

Re: Circular logic with rule 12.1

Post by jbrookley » Mon Oct 28, 2013 10:31 pm

Just a heads up, I am able to fix it with:

Code: Select all

BurnCount = (ushort16)(EEPROM_BANK0[1]) + (ushort16)((ushort16)(EEPROM_BANK0[0]) << 8u);
BurnCount += 1u;
But I would still like to understand what is wrong with my other attempts so that I can better understand the MISRA requirement. Thanks!

Steve Montgomery
Posts: 104
Joined: Fri Sep 17, 2004 1:31 pm
Company: .
Location: Northumberland or Isle of Skye

Re: Circular logic with rule 12.1

Post by Steve Montgomery » Tue Oct 29, 2013 11:28 am

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: Select all

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: Select all

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: Select all

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: Select all

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.

jbrookley
Posts: 12
Joined: Thu Aug 08, 2013 5:56 pm
Company: Kavlico

Re: Circular logic with rule 12.1

Post by jbrookley » Tue Oct 29, 2013 7:58 pm

Interesting, you hit it right on the head with the different data types. I changed it to:

Bur

Code: Select all

nCount = (ushort16)(EEPROM_BANK0[1]) + (ushort16)((ushort16)(EEPROM_BANK0[0]) << 8u) + (ushort16)1u;
and it seems to have worked itself out. I'll have to keep this in mind for some of the other applications I have. I just thought I'd post a reply in case anyone else is having the same issue. Thanks again!

misra-c
Posts: 572
Joined: Thu Jan 05, 2006 1:11 pm

Re: Circular logic with rule 12.1

Post by misra-c » Thu Dec 12, 2013 9:07 am

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.
---
Posted by and on behalf of
the MISRA C Working Group

Post Reply

Return to “6.12 Expressions”