views:

294

answers:

3

Using V1.8 z/OS XL C compiler, with warnings jacked-up using INFO(ALL), I get the following warning on line 4 of the code below:

WARNING CCN3196 Initialization between types "const int** const" and "int**" 
                is not allowed.


1  int foo = 0;
2  int *ptr = &foo;

3  const int * const fixed_readonly_ptr = ptr;

4  const int ** const fixed_ptr_to_readonly_ptr = &ptr;

I can't wrap my head around why I'm getting this warning. If I can assign an int pointer to a const pointer to const int (line 3), then why can't I assign the address of an int pointer to a const pointer to pointer to const int? What am I missing?

Note the code above is a slimmed down example just showing the issue I'm encountering in a small amount of code. The real context is that I have a const pointer to pointer to struct (struct s** const) and am passing it as an argument to a function who's parameter is defined as a const pointer to pointer to const struct (const struct s** const). This is because the function will not modify the data in the struct (hence the first const) and it does not modify the pointer parameter which always holds the address passed in (hence the second const). The value of the pointer pointed to may be changed by the way (which is why there is NOT a third const in between the **).

+3  A: 

It's a type safety violation. Consider this code (I shuffled const around a bit to make it clear whether it applies to pointer or pointee, but semantically it means exact same thing):

int* p = 0;
int const** pp = &p; // presumably ok

int const c = 123;
*pp = &c; // okay, &c is int const*, and *p is int const* lvalue

*p = 666; // okay, *p is int lvalue

// wait, so we just changed the value of (const) c above, with no const_cast!
Pavel Minaev
+2  A: 

The C rule is that you can convert a pointer to something to a pointer to const something, but that something has to be exactly the same type including const and volatile qualifications further down the chain.

The rationale for this rule is that if the second of these two lines were allowed:

int *ptr;

const int ** const fixed_ptr_to_readonly_ptr = &ptr;

then this can be used to break type safety without a cast.

const int i = 4;

// OK, both sides have type const int *
*fixed_ptr_to_readonly_ptr = &i;

// the value of fixed_ptr_to_readonly_ptr is still &ptr
// the value of ptr is now &i;

*ptr = 5;

// oops, attempt to change the value of i which is const
Charles Bailey
A: 

This is a type-safety violation. You probably want to use a const int * const * instead. See http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

Geerad
`const int * const *` only helps in C++, not C
Charles Bailey