c++castingreinterpret-caststatic-castconst-cast

Why type casting of const void* is legal in C not C++ without using static_cast


There are a couple of questions with similar names on StackOverflow, such as this one and this one .etc

However, none of them answered the questions in my mind...

Problem Background:

I'm including a C header file in C++ code. The problematic C code is shown below:

// C header file
static inline bool post_request(const customer_t *requester, const void *packagevoid)
{
    const pkg_req_t *pkg = packagevoid;
    ...
    ... // some other code
}

The compiler complained that:

/<project_path>/handler_util.h:250:26: error: invalid conversion from 'const void*' to 'const const pkg_req_t*' {aka 'const pkg_req_s*'} [-fpermissive]
const pkg_req_t *pkg = packagevoid;
                       ^~~~~~~

I changed the conversion to explictly use static_cast:

// C header file: fixed
static inline bool post_request(const customer_t *requester, const void *packagevoid)
{
#ifdef __cplusplus
  const pkg_req_t *pkg = static_cast<const pkg_req_t*>(packagevoid);
#else
   const pkg_req_t *pkg = packagevoid;
#endif
    ...
    ... // some other code
}

Questions:

  1. const pkg_req_t *pkg = packagevoid; --- why this is legal in C but giving error in C++?
  2. Is static_cast an elegant solution in this case? --- I'm asking this question because it appears that const_cast<pkg_req_t*>reinterpret_cast<const pkg_req_t*> also works. Which one is better?
  3. In the compilation error message, why is the compiler reporting "[-fpermissive]" in the end of the error message?

Solution

  • why this is legal in C but giving error in C++?

    In C++, implicit conversion from void* to T* is not allowed because it is not a "safe" conversion. Dereferencing the T* would cause undefined behaviour unless the void* actually did point to a T object.

    By the time C++ was created, it was too late to ban this type of implicit conversion in C because it would break all the code that does this:

    T* p = malloc(sizeof(T));  // malloc returns void*
    

    Therefore, it continues to be allowed in C.

    Is static_cast an elegant solution in this case?

    Yes, that's the "best practices" way to perform a conversion from const void* to const T*.

    static_cast is less dangerous than const_cast and reinterpret_cast, so it should be preferred over them. dynamic_cast is less dangerous than static_cast, but it cannot be used in this situation.

    In the compilation error message, why is the compiler reporting "[-fpermissive]" in the end of the error message?

    The compiler is telling you that if you compile your code with the -fpermissive flag, it will accept the implicit conversion from const void* to const T* even though the standard does not allow it.