Considering the following code (and the fact that VirtualAlloc()
returns a void*
):
BYTE* pbNext = reinterpret_cast<BYTE*>( VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));
why is reinterpret_cast
chosen instead of static_cast
?
I used to think that reinterpret_cast
is OK for e.g. casting pointers to and from integer types (like e.g. DWORD_PTR
), but to cast from a void*
to a BYTE*
, isn't static_cast
OK?
Are there any (subtle?) differences in this particular case, or are they just both valid pointer casts?
Does the C++ standard have a preference for this case, suggesting a way instead of the other?
Pointer is merely a memory address. With typecasting, any type with enough size to hold the memory address can work like a pointer.
In plain C you can cast any pointer type to any other pointer type.
padd = (Addition*) &d; Unrestricted explicit type-casting allows to convert any pointer into any other pointer type, independently of the types they point to. The subsequent call to member result will produce either a run-time error or some other unexpected results.
For convertible pointers to fundamental types both casts have the same meaning; so you are correct that static_cast
is okay.
When converting between some pointer types, it's possible that the specific memory address held in the pointer needs to change.
That's where the two casts differ. static_cast
will make the appropriate adjustment. reinterpret_cast
will not.
For that reason, it's a good general rule to static_cast
between pointer types unless you know that reinterpret_cast
is desired.
You should static_cast
. Use static_cast
in cases where you're undoing an implicit conversion.
In this particular case, however, there is no difference because you're converting from void*
. But in general, reinterpret_cast
ing between two object pointers is defined to be (§5.2.10/7):
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue
v
of type “pointer toT1
” is converted to the type “pointer to cvT2
”, the result isstatic_cast<cv T2*>(static_cast<cv void*>(v))
if bothT1
andT2
are standard-layout types and the alignment requirements ofT2
are no stricter than those ofT1
, or if either type isvoid
. Converting a prvalue of type “pointer toT1
” to the type “pointer toT2
” (whereT1
andT2
are object types and where the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
Emphasis mine. Since T1
for you is already void*
, the cast to void*
in reinterpret_cast
does nothing. This is not true in general, which is what Drew Dormann is saying:
#include <iostream> template <typename T> void print_pointer(const volatile T* ptr) { // this is needed by oversight in the standard std::cout << static_cast<void*>(const_cast<T*>(ptr)) << std::endl; } struct base_a {}; struct base_b {}; struct derived : base_a, base_b {}; int main() { derived d; base_b* b = &d; // implicit cast // undo implicit cast with static_cast derived* x = static_cast<derived*>(b); // reinterpret the value with reinterpret_cast derived* y = reinterpret_cast<derived*>(b); print_pointer(&d); print_pointer(x); print_pointer(y); }
Output:
00CBFD5B
00CBFD5B
00CBFD5C
(Note that because y
doesn't actually point to a derived
, using it is undefined behavior.)
Here, reinterpret_cast
comes up with a different value because it goes through void*
. This is why you should use static_cast
when you can, and reinterpret_cast
when you have to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With