Reputation: 599
The following MISRA violations appeared while analyzing the following code:
#define z (USHORT)14745
#define Convert(x) ((((USHORT)x*(unsigned short)1000) + ((z) / (USHORT)2)) /(z))
static const USHORT array [2] =
{
Convert(176), -> Line "1"
Convert(206) -> Line "2"
};
The following MISRA violations are detected on both lines "1", "2":
Integral promotion : unsigned short promoted to unsigned int. REFERENCE - ISO:C90-6.2.1.1 Characters and Integers
Constant: Wraparound in unsigned arithmetic operation. MISRA-C:2004 Rule 12.11; REFERENCE - ISO:C90-6.1.2.5 Types
The result of this cast is implicitly converted to another type.
My question is: Why there will be a wraparound in this operation ?!
Note: When I am checking the values of array
with debugger:
array [2] =
{
12,
14
}
which are the correct values.
Upvotes: 0
Views: 2366
Reputation: 599
It is related to Integral Promotion:
Integer types smaller than int are promoted when an operation is performed on them. If all values of the original type can be represented as an int, the value of the smaller type is converted to an int; otherwise, it is converted to an unsigned int.
So that, the macro Convert(206) [((((unsigned short)206*(unsigned short)1000) + ((z) / (USHORT)2)) /(z))]
will be executed as following:
Upvotes: 0
Reputation: 213832
First of all, 176 * 1000 will not fit inside a 16 bit unsigned short. So by using MISRA, you prevented severe bugs in your code, because the algorithm was calculated on signed int
type and the result of it implicitly showed back into an unsigned short. If you get the expected results, it is entirely by coincidence/luck.
Note that there are two other advisory MISRA violations that weren't reported:
stint.h
(rule 6.3)Both of these are very good rules and not something you should ignore. (Also it should have warned about you using literals without 'u' suffix.)
The fix is to replace the messy macro with a type safe function, that contains no implicit promotions (given 32 bit int
):
uint16_t convert (uint16_t x)
{
const uint16_t z = 14745u;
uint32_t result32;
result32 = (uint32_t)x * 1000ul + (uint32_t)z / 2ul / (uint32_t)z
return (uint16_t)result32;
}
Upvotes: 1