Why is this an issue?
C++ allows the traditional C-style casts [E.G. (int) f
] and functional notation casts [E.G. int(f)
], but adds its own
forms:
-
static_cast<type>(expression)
-
const_cast<type>(expression)
-
dynamic_cast<type>(expression)
-
reinterpret_cast<type>(expression)
-
std::bit_cast<type>(expression)
(since C++20)
C-style casts and functional notation casts are largely functionally equivalent. However, when they do not invoke a converting constructor, C-style
casts are capable of performing dangerous conversions between unrelated types and of changing a variable’s const
-ness. Attempt to do
these things with an explicit C++-style cast, and the compiler will catch the error. Use a C-style or functional notation cast, and it cannot.
Moreover, C++20 has introduced a std::bit_cast
as a way of reinterpreting a value as being of a different type of the same length
preserving its binary representation. The behavior of such conversion when performed via C-style cast or reinterpret_cast
is
undefined.
Additionally, C++-style casts are preferred because they are visually striking. The visual subtlety of a C-style or functional cast may mask that a
cast has taken place, but a C++-style cast draws attention to itself, and makes the the programmer’s intention explicit.
This rule raises an issue when C-style cast or functional notation cast is used.
Noncompliant code example
#include <iostream>
class Base { };
class Derived: public Base
{
public:
int a;
};
void DoSomethingElse(Derived *ptr)
{
ptr->a = 42;
}
void DoSomething(const Base *ptr)
{
Derived* derived = (Derived*)ptr; // Noncompliant; inadvertently removes constness
DoSomethingElse(derived);
}
void checksBits(float f)
{
int x = *(int*)&f; // Noncompliant; has undefined behavior
}
int main(int argc, char* argv[])
{
Derived *ptr = new Derived();
ptr->a = 1337;
DoSomething(ptr);
std::cout << ptr->a << std::endl; /* 1337 was expected, but 42 is printed */
return 0;
}
Compliant solution
/* ... */
void DoSomething(const Base *ptr)
{
/* error: static_cast from type 'const Base*' to type 'Derived*' casts away qualifiers */
Derived* derived = static_cast<Derived*>(ptr); // Compliant. Compile fails with above error
DoSomethingElse(derived);
}
void checksBits(float f)
{
int x = std::bit_cast<int>(f);
}
/* ... */
Exceptions
Void casts and explicit constructor calls are allowed.
Resources
- MISRA C++:2008, 5-2-4 - C-style casts (other than void casts) and functional notation casts (other than explicit constructor calls) shall not
be used.