I don't understand why I need to do this cast operation here, when I
don't need to do a (const uint8_t *) cast in get_ptr1.
The C language spec's applicable rule for simple assignment where both operands have pointer types other than pointers to void is:
the left operand has atomic, qualified, or unqualified pointer type,
and (considering the type the left operand would have after lvalue
conversion) both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to by the left
operand has all the qualifiers of the type pointed to by the right
operand
In that light, consider first the working alternative:
void get_ptr1(const S1_t *s1, uint8_t const **ptr1)
{
*ptr1= s1->ptr1;
}
*ptr1 has type uint8_t const *, and its pointed-to type is uint8_t const.
s1->ptr1 has type uint8_t *, and its pointed to type is uint8_t.
Now evaluate the constraint:
"both operands are pointers to qualified or unqualified versions of compatible types" -- yes. both are pointers to qualified or unqualified versions of uint8_t.
"the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand" -- yes, trivially, because the type pointed to by the right operand is unqualified.
Now consider the non-working example:
void get_ptr2(const S1_t *s1, uint8_t const *const **ptr2)
{
*ptr2 = s1->ptr2;
}
*ptr2 has type uint8_t const * const *, and its pointed-to type is uint8_t const *.
s1->ptr2 has type uint8_t **, and its pointed to type is uint8_t *.
Now evaluate the constraint:
- "both operands are pointers to qualified or unqualified versions of compatible types" -- NO.
uint8_t const * const * and uint8_t ** are neither compatible types (which for pointer types means the same type), nor differently-qualified versions of compatible types.
For that, you need to understand that the "differently qualified" applies to the type itself, not to any other types in its derivation. Thus, int * and int * const are differently qualified pointers to int. int * and const int * are identically (un)qualified pointers to different types (int and const int). And as for uint8_t ** and uint8_t * const * const, these are differently qualified pointers to different types.
It's not entirely clear what you're trying to achieve via the const-qualification, but the ptr2 analog of your get_ptr1() would be
void get_ptr2(const S1_t *s1, uint8_t * const **ptr2)
{
*ptr2 = s1->ptr2;
}
uint8_t const *const **ptr2make any sense? What you actually should be doing is probablyconst uint8_t* get_ptr1 (const S1_t* s1);But exposing private members through pointers is often bad design in the first place, const or not.T **cannot be automatically converted toconst T **is explained here. This also prevents automatic conversion toconst T * const *.