Home > Enterprise >  cast const pointers to void * in C
cast const pointers to void * in C

Time:08-27

I have the following code that does not compile with gcc 10.2.1 :

struct Bar {
    unsigned char *m_a;
    unsigned char m_b[1];
};

int main()
{
    Bar bar;
    const Bar &b = bar;

    void *p1 = b.m_a; // Ok
    void *p2 = b.m_b; // Error

    return 0;
}

The compiler error is :

error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]

I can fix this by using either void *p2 = (void *)b.m_b; or void *p2 = const_cast<unsigned char *>(b.m_b); however, constness of members does not seem to be treated the same by the compiler.

I guess there is an "extra-check" for the array and not with the pointer but why is that ?

Thank you.

CodePudding user response:

Having a const struct adds const to all the members.

Adding const to unsigned char * gives you unsigned char * const (i.e., the pointer cannot be changed to point to anything else, but you can change the value of what is pointed to). This can be cast to void *, since that is also a pointer to non-const.

Adding const to unsigned char[1] gives you const unsigned char[1] (A const array of T is actually an array of const T). This can decay into a const unsigned char * pointer, which can be cast to a const void *, but not a void * without casting away the const. This is because the elements of the array cannot be modified, unlike the pointed-at object with the first member.

CodePudding user response:

b.m_a

This is an unsigned char *. It is happy to be converted to a void *.

b.m_b

This is a const unsigned char *. That's how arrays work in C and C : the name of the array decays to a pointer to the first value in the array. This array is const, therefore this becomes a const unsigned char *, and you can't convert it to a void *.

Note that you'll get the same error if you attempt to convert &b.m_a to a void *.

b.m_a itself is const, but it's not pointing to a const object. These are two very different things: a const pointer and a pointer to a const.

CodePudding user response:

The expression b is of type const Bar meaning the data member m_a is unsigned char *const and m_b is const unsigned char [1].

Now, the important thing to note is that:

a pointer to any nonconst type can be converted to void*, and a pointer to any type can be converted to a const void*

(emphasis mine)Source

This means that b.m_a can be implicitly converted to a void* and b.m_b can be implicitly converted to const void* and not void*.

Thus to solve your problem, you should add a low-level const to p2 as shown below:

vvvvv-------------------->low level const added
const void *p2 = b.m_b; // works now

Demo

  • Related