Search code examples
c++pointersvoid-pointersreinterpret-castdouble-pointer

Is it Legal to reinterpret_cast to a void*


I was looking at https://en.cppreference.com/w/cpp/language/reinterpret_cast and I noticed that it specifies the legal types we can always cast to:

  • byte*
  • char*
  • unsigned char*

But I did not see void* in the list. Is this an oversight? My use case requires a reinterpret_cast because I'm casting from an int** to a void*. And I will eventually cast from the void* back to an int**.


Solution

  • It is always legal to convert from a pointer to a type to a pointer to a different type including void, so if T is a type this is legal C++:

    T* x;
    void *y = reinterpret_cast<void *>(x);
    

    In real world it is never used because void * is a special case, and you obtain the same value with static_cast:

    void *y = static_cast<void *>(x); // equivalent to previous reinterpret_cast
    

    (in fact above conversion is implicit and can be simply written void *y = x; - thank to Michael Kenzel for noticing it)

    To be more explicit the standard even says in draft n4659 for C++17 8.2.10 Reinterpret cast [expr.reinterpret.cast], §7

    When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v)).

    When you refer to byte and char being the only legal types, it is just that it is legal to dereference the converted pointer only for those types. void is not included here because you can never dereference a void *.


    To specifically answer your question

    .. I'm casting from an int** to a void*. And I will eventually cast from the void* back to an int**.

    The standard guarantees that first one is a standard (read implicit) conversion:

    A prvalue of type “pointer to cv T”, where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The pointer value (6.9.2) is unchanged by this conversion.

    So this is always legal:

    int **i = ...;
    void *v = i;
    

    For back casting, standard says (in static_cast paragraph):

    A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”,

    So this is also legal

    int **j = static_cast<int **>(v);
    

    and the standard ensures that j == i.