Инициализация между типами «const int** const» и «int**» не допускается, почему?
Вопрос
Используя компилятор C v1.8 z/OS XL с предупреждениями, поднятыми с помощью INFO(ALL), я получаю следующее предупреждение в строке 4 приведенного ниже кода:
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;
Я не могу понять, почему я получаю это предупреждение.Если я могу назначить указатель int константному указателю на const int (строка 3), то почему я не могу присвоить адрес указателя int константному указателю на const int?Что мне не хватает?
Обратите внимание, что приведенный выше код представляет собой уменьшенный пример, просто показывающий проблему, с которой я столкнулся в небольшом объеме кода.Реальный контекст таков, что у меня есть константный указатель на указатель на структуру (struct s** const), и я передаю его в качестве аргумента функции, параметр которой определен как константный указатель на указатель на const struct (const struct s** константа).Это связано с тем, что функция не будет изменять данные в структуре (отсюда первая константа) и не изменяет параметр-указатель, который всегда содержит переданный адрес (отсюда и вторая константа).Значение указателя, на который указывает, может быть изменено (именно поэтому между ** НЕТ третьей константы).
Решение
Правило C заключается в том, что вы можете преобразовать указатель на что-то в указатель на что-то константное, но это что-то должно быть точно такого же типа, включая константные и изменчивые квалификации, расположенные дальше по цепочке.
Обоснование этого правила заключается в том, что если бы была разрешена вторая из этих двух строк:
int *ptr;
const int ** const fixed_ptr_to_readonly_ptr = &ptr;
тогда это можно использовать для нарушения безопасности типов без приведения типов.
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
Другие советы
Это нарушение типовой безопасности.Рассмотрим этот код (я перетасовал const
немного, чтобы прояснить, относится ли это к указателю или указателю, но семантически это означает одно и то же):
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!
Это нарушение типовой безопасности.Вероятно, вместо этого вы захотите использовать const int * const *.Видеть http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17