1

I know that reinterpret_cast is primarily used going to or from a char*.

But I was surprised to find that static_cast could do the same with a void*. For example:

auto foo "hello world"s;
auto temp = static_cast<void*>(&foo);
auto bar = static_cast<string*>(temp);

What do we gain from using reinterpret_cast and char* over static_cast and void*? Is it something to do with the strict aliasing problem?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    Generally you cast to a `char*` do do something with the individual bytes. You cannot do that with a `void*`. – NathanOliver Sep 22 '16 at 18:52
  • @NathanOliver So you're saying like `memcpy` or similar? – Jonathan Mee Sep 22 '16 at 18:53
  • 1
    Well `memcpy` is one of them. The `read` and `wrtie` function of streams are others. If you need to send stuff over com data you would also do this. – NathanOliver Sep 22 '16 at 19:02
  • @NathanOliver I guess the point here is that `void*` is a considered in the hierarchy of any type while a `char*` is not? That's the reason this `static_cast` is allowed? But then I guess at the end of the day, the answer to my question is none of the std library functions are looking for a `void*` so why would I even use this type. – Jonathan Mee Sep 22 '16 at 19:22
  • @CaptainObvlious Can you point me to a section in that answer which answers the question: "What do we gain from using `reinterpret_cast` and `char*` over `static_cast` and `void*`?" Perhaps I'm missing it, but I really don't see it. – Jonathan Mee Sep 22 '16 at 19:38
  • 1
    Reopened. This is not about which cast to use; it's about the peculiar behavior of `void*`. – Pete Becker Sep 22 '16 at 19:48

2 Answers2

0

Generally speaking, static_cast will do cast any two types if one of them can be cast to the other implicitly. That includes arithmetic casts, down-casts, up-casts and cast to and from void*.

That is, if this cast is valid:

void foo(A a);
B b;
foo(b);

Then the both static_cast<B>(a) and static_cast<A>(b) will also be valid.

Since any pointer can be cast implicitly to void*, thus your peculiar behavior.

reinterpret_cast do cast by reinterpreting the bit-pattern of the values. That, as you said in the question, is usually done to convert between unrelated pointer types.

Yes, you can convert between unrelated pointer types through void*, by using two static_cast:

B *b;
A *a1 = static_cast<A*>(b); //compiler error
A *a2 = static_cast<A*>(static_cast<void*>(b)); //it works (evil laugh)!

But that is bending the rules. Just use reinterpret_cast if you really need this.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
0

Your question really has 2 parts:

  1. Should I use static_cast or reinterpret_cast to work with a pointer to the underlying bit pattern of an object without concern for the object type?
  2. If I should use reinterpret_cast is a void* or a char* preferable to address this underlying bit pattern?

static_cast: Converts between types using a combination of implicit and user-defined conversions

In 5.2.9[expr.static.cast]13 the standard, in fact, gives the example:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));

It leverages the implicit cast:

A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void. The resulting pointer represents the same location in memory as the original pointer value. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.*

There is however no implicit cast from a pointer of type T to a char*. So the only way to accomplish that cast is with a reinterpret_cast.

reinterpret_cast: Converts between types by reinterpreting the underlying bit pattern

So in answer to part 1 of your question when you cast to a void* or a char* you are looking to work with the underlying bit pattern, reinterpret_cast should be used because it's use denotes to the reader a conversion to/from the underlying bit pattern.

Next let's compare void* to char*. The decision between these two may be a bit more application dependent. If you are going to use a standard library function with your underlying bit pattern just use the type that function accepts:

  • void* is used in the mem functions provided in the cstring library
  • read and write use char* as inputs

It's notable that C++ specific libraries prefer char* for pointing to memory. Holding onto memory as a void* seems to have been preserved for compatibility reasons as pointer out here. So if a cstring library function won't be used on your underlying bit patern, use the C++ specific libraries behavior to answer part 2 of your question: Prefer char* to void*.

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288