и вы не получите то же самое предупреждение. Кроме того, вы можете разыграть v
, когда вы звоните f
Вы можете использовать pointer-to-T
(для любого типа T
), где ожидается pointer-to-const-T
. Однако правило (явное исключение), допускающее небольшие несоответствия в квалифицированных типах указателей, применяется не рекурсивно, а только на верхнем уровне. (const char **
равно pointer-to-pointer-to-const-char
, и, следовательно, исключение не применяется.)
Причина, по которой вы не можете присвоить значение char **
указателю const char **
, несколько неясна. Учитывая, что классификатор const
существует вообще, компилятор хотел бы помочь вам выполнить ваши обещания не изменять значения const
. Вот почему вы можете назначить char *
для const char *
, но не наоборот: совершенно очевидно, что добавить const
-ность к простому указателю, но это опасно это прочь Однако предположим, что вы выполнили следующую более сложную серию заданий:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
В строке 3 мы присваиваем char **
const char **
. (Компилятор должен пожаловаться.) В строке 4 мы присваиваем const char *
a const char *
; это явно законно. В строке 5 мы модифицируем то, на что указывает char *
- это должно быть законно. Однако p1 в конечном итоге указывает на c, который равен const
. Это произошло в строке 4, потому что * p2 был действительно p1. Это было установлено в строке 3, которая является назначением запрещенной формы, и именно поэтому строка 3 запрещена.
Назначение char **
для const char **
(как в строке 3 и в исходном вопросе) не является сразу же опасным. Но он создает ситуацию, в которой обещание p2 - что конечное значение не будет изменено - не может быть выполнено.
(C ++ имеет более сложные правила для назначения const
-качественных указателей, которые позволяют выполнять больше видов назначений без появления предупреждений, но при этом защищают от непреднамеренных попыток изменить значения const
. C ++ по-прежнему не позволяет назначать char **
для const char **
, но это позволит вам присвоить char **
для const char * const
*.)
В C, если вы должны назначить или передать указатели, которые имеют несоответствия в квалификаторах, отличные от первого уровня косвенности, вы должны использовать явное приведение (например, (const char **
) в этом случае), хотя, как всегда, необходимость такое приведение может указывать на более глубокую проблему, которую на самом деле не решают.
Ссылки: ISO Sec. 6.1.2.6, гл. 6.3.16.1, гл. 6.5.3
H & S Sec. 7,9,1 с. 221-2