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 aconst 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