I receive a pointer p to a struct S from C code and want to downcast it in C++ with
static_cast<S_extended*>(p)
where
S_extended is derived from S but just adds some methods to S so that the struct remains trivial and having standard layout (no virtual functions, no special functions, etc. are added).
No new data members are added into derived class.
Does such casting cause undefined behavior?
For example,
typedef struct S{
uint32_t data;
} S;
struct S_extended
: public S {
uint32_t getData(){return data;}
};
S s = {1};
uint8_t f(){
return static_cast<S_extended*> (&s) -> getData(); // UB ???
}
What you are attempting to do is UB in multiple ways. Let's start with the fact that down-casting to a derived class isn't possible as per C++23 [expr.static.cast] p2 if you don't have an object of the derived type.
Even if it was possible to static_cast
in this case, you would immediately run into another form of undefined behavior. Up until C++20, this would be:
If a non-static member function of a class
X
is called for an object that is not of typeX
, or of a type derived fromX
, the behavior is undefined.
- C++20 [class.mfct.non-static.general] p2
S
is not the same type as S_extended
or derived from S
, and you are calling a member function of S_extended
for an object of type S
. The behavior is undefined.
In C++23, this requirement was generalized for member access E1.E2
:
If
E2
is a non-static member and the result ofE1
is an object whose type is not similar to the type ofE1
, the behavior is undefined.
Note that similar means S
and S_extended
would need to be pretty much the same type, and they are not.
Note: This C++23 change was made in CWG2535 Type punning in class member access