This rule is part of MISRA C++:2023.
Usage of this content is governed by Sonar’s terms and conditions. Redistribution is
prohibited.
Rule 7.0.5 - Integral promotion and the usual arithmetic conversions shall not change the signedness or the type
category of an operand
[conv.prom]
[conv.fpprom]
[conv.integral]
[conv.double]
[conv.fpint]
[conv.rank]
[expr]
Category: Required
Analysis: Decidable,Single Translation Unit
Amplification
This rule applies to all expressions (including sub-expressions) of numeric type. It also applies within preprocessing directives, with
the provision that expressions used in #if and #elif preprocessor directives always have the type intmax_t or
uintmax_t.
For the usual arithmetic conversions, only the final type of an operand is considered. For example, in the expression u32 +
u8, u8 is first converted to signed int through integral promotion before being converted to
uint32_t; it is the final type of uint32_t that is considered by this rule.
This rule does not apply to the integral promotion of the operand to the increment or decrement operators.
Rationale
Integral promotion and the usual arithmetic conversions are usually value-preserving conversions, and it may therefore appear
that they are always safe. However, the signedness of the converted type may, possibly surprisingly, not be the same as the signedness of the operand.
For example, when an unsigned type is converted to a signed type, an operation may overflow and trigger undefined behaviour instead of
wrapping.
The increment and decrement operators convert their results to the type of their operand. This may be a lossy, narrowing conversion, but the
usefulness of these operators outweighs this risk.
Exception
- A compile-time constant with signed integral type that has a non-negative value may be converted to an unsigned type through the usual
arithmetic conversions.
- A compile-time constant with integral type may be converted to a floating type.
Example
The following non-compliant examples do not directly pose a problem. However, using their results could lead to surprising or undefined
behaviour.
u8a + u8b // Non-compliant - u8a and u8b -> signed int
u8a += u8b // Non-compliant - same as u8a + u8b
static_cast< uint32_t >( u8a ) + u8b // Compliant - u8b -> unsigned int
u8a += static_cast< uint32_t >( u8b ) // Compliant - u8a -> unsigned int
s32 * s8 // Compliant - s8 -> signed int
u32 / u8 // Compliant - u8 -> unsigned int
s32 > u32 // Non-compliant - s32 -> unsigned int
u32a - 1 // Compliant by exception #1
b ? u8a : u8b // Compliant - no conversion
b ? u8a : u16a // Non-compliant - u8a -> signed int and
// u16a -> signed int
array[ u8 ] // Rule does not apply - no conversion of u8
u8++ // Rule does not apply
f32 += u32 // Non-compliant - u32 -> floating
f32 += 1 // Compliant by exception #2
f32 += 0x100'0001 // Compliant by exception #2 - precision lost
~u8 // Non-compliant - u8 -> signed int
~u32 // Compliant
-u8 // Non-compliant - u8 -> signed int
u8 << 2 // Non-compliant - u8 -> signed int
constexpr int32_t fn( int32_t i )
{
return i * i;
}
u8 + fn( 10 ) // Compliant by exception #1
f32 + fn( 10 ) // Compliant by exception #2
Copyright The MISRA Consortium Limited © 2023