0

Does it generally hold true that static_cast<T*>(static_cast<void*>(a)) == reinterpret_cast<T*>(a) for some type a that can be casted to T*. What cases will this not be true? I have an example below that shows a case where this holds true:

#include <iostream>
#include <string>

int main() {
  std::string a = "Hello world";
  float* b = static_cast<float*>(static_cast<void *>(&a[0]));
  float* c = reinterpret_cast<float*>(&a[0]);
  std::cout << (b == c) << std::endl; // <-- This prints 1 
}

Please let me know if my question is unclear.

dbep
  • 647
  • 6
  • 20
  • Are you asking if this will "generally" work, or if it is defined behaviour or not? –  Aug 22 '18 at 21:00
  • @NeilButterworth The code illustrates the question. The question isn't precisely about the code. – François Andrieux Aug 22 '18 at 21:01
  • 2
    Possible duplicate of [reinterpret\_cast(p) or static\_cast((void\*)p)) for bytewise pointer difference, which is better?](https://stackoverflow.com/questions/25638770/reinterpret-castcharp-or-static-castcharvoidp-for-bytewise-pointer) – Justin Aug 22 '18 at 21:02
  • Not directly the question but [note strict aliasing issues](https://stackoverflow.com/a/51228315/1708801) – Shafik Yaghmour Aug 22 '18 at 21:03

1 Answers1

0

Static casting to/from void* of another pointer is the same as reinterpret_casting.

Using a pointer to a non-float as a pointer to a float can be UB, including things as innocuous as comparing one pointer value to another.

A hardware reason behind this is that on some platforms, floats have mandatory alignment, and == on two float* may assume that they are pointing to aligned values. On at least one platform, both char* and void* take up more memory than a float* because there is no byte-addressing on the platform; byte addressing is emulated by storing an additional "offset" and doing bitmasking operations under the hood.

On other platforms, different address spaces entirely are used for different types of pointers. One I'm aware of has function and value address spaces being distinct.

The standard, mindful of such quirks and in order to permit certain optimizations, does not fully define what happens when you use incorrectly typed pointers. Implementations are free to document that they behave like a flat memory model that you might expect but are not mandated to.

I cannot remember if this is implementation defined (which means they must document if it is defined or UB) or just UB here (which means compilers are free to define its behavior, but do not have to).

For types that where the T* is fully valid and proper (ie, there is actually an object of type T there, we just had a pointer to void* or char* to it, or somesuch), then static_cast<T*>(static_cast<void*>(addy)) == reinterpret_cast<T*>(addy) in every case.

Aliasing issues -- having pointers to the wrong type -- are very tricky.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524