I have a method returning a templated class and taking as argument another templated class such as :
template <class T, class U>
T caster(U* u)
{
return reinterpret_cast<T>(u);
}
Compiling with an ARM compiler, i get a cast-align error returned by my compiler which understandable because in my example bellow, char and int do not have the same alignment. As i know that reinterpret_cast is not that such of a good practice, i tried the following changes :
template <class T, class U>
T caster(U* u)
{
T tmp;
std::memcpy(&tmp, u, sizeof(U));
return tmp;
}
int main()
{
int32_t test = 50000;
auto tmp = caster<char, int32_t>(&test);
return 0;
}
But this time i get a stack smashing detected error which is equivalent i believe to a kind of overflow.
What am I doing wrong ? Based on 2 unknown types, how can i properly cast U to T taking into account alignment ?
T tmp; std::memcpy(&tmp, u, sizeof(U)); return tmp;
The obvious issue here is that you're copying sizeof(U)
bytes into T
, even though T
may be smaller or larger.
T
is larger, it's possible that some bytes of tmp
are left indeterminateT
is smaller, you write past the end of tmp
T = char
and U = int32_t
because three bytes are written past the end of tmp
If anything, it should be sizeof(T)
or sizeof(tmp)
:
template <class T>
T caster(void* memory) {
T tmp;
// It's still possible that we cannot read sizeof(T) bytes from memory,
// but that's on the caller, and at least we never smash the stack.
std::memcpy(&tmp, memory, sizeof(T));
return tmp;
}
Notice that what you're making here is a poor-man's std::bit_cast
.
It's one of the ways to do type punning in modern C++.
reinterpret_cast
virtually never is.