Search code examples
cpointersgccgcc-warning

Incompatible pointer type assignment for double pointer to constant double pointer


I have the following code:

typedef struct S1 S1_t;
struct S1
{
  uint8_t *ptr1;
  uint8_t **ptr2;
};

void get_ptr1(const S1_t *s1, uint8_t const **ptr1)
{
  *ptr1= s1->ptr1;
}

void get_ptr2(const S1_t *s1, uint8_t const *const **ptr2)
{
  *ptr2 = s1->ptr2;
}

If I leave it like that, I get the following warning from the GCC compiler for the function get_ptr2:

assignment to ‘const uint8_t * const*’ {aka ‘const unsigned char * const*’} from incompatible pointer type ‘uint8_t **’ {aka ‘unsigned char **’}

In order for me to mute the warning, I have to cast s1->ptr2 before assigning it to ptr2:

void get_ptr2(const S1_t *s1, uint8_t const *const **ptr2)
{
  *ptr2 = (const uint8_t *const *)s1->ptr2;
  return 0;
}

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?

My goal here is to implement getter functions for the structure S1's members, and I want to make sure the function getting those members cannot modify them. Is the compiler throwing a warning at me because I am doing something dangerous here?

I have the -wall and -wextra compilation option flag enabled.


Solution

  • While it's allowed to assign a pointer to a non-const type to a pointer to a const type, that only applies to the first "level" of pointer. If this were allowed, it would be possible to allow a const object to be modified.

    For example:

    const char c = 1;
    const char *p1 = &c;
    char *p2;
    char **pp1 = &p2;
    const char **pp2 = pp1;    // invalid char ** to const char ** conversion
    *pp2 = p1;                 // p2 now points to c (no warning!)
    *p2 = 2;                   // modifying a const object (no warning!), UB
    

    In the above case is slightly different from yours since only the "outer level" is const. If pp2 were defined as const char * const *pp2 then this wouldn't be possible, as the line *pp2 = p1; would contain an error. This is really a defect in the C standard that your case isn't allowed, given that each pointer level in the destination type is const qualified.

    Applying a cast, as you've done, is the appropriate fix for this case.