为什么将“pointer to pointer to non-const”转换为“指向const的指针”是不合法的,

将指向非const的指针转换成指向const的指针合法的。

那么为什么把一个指针指向非const指针转换为指向const指针是不合法的呢?

例如,为什么下面的代码是非法的:

char *s1 = 0; const char *s2 = s1; // OK... char *a[MAX]; // aka char ** const char **ps = a; // error! 

从标准:

 const char c = 'c'; char* pc; const char** pcc = &pc; // not allowed *pcc = &c; *pc = 'C'; // would allow to modify a const object 

正因为没有人发布解决scheme ,在这里:

 char *s1 = 0; const char *s2 = s1; // OK... char *a[MAX]; // aka char ** const char * const*ps = a; // no error! 

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17为什么);

忽略你的代码,并回答你的问题的原则,请参阅comp.lang.c FAQ条目: 为什么我不能传递一个char **到一个const char **函数?

你不能给const char **指针赋值char **的原因有些模糊。 鉴于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 *赋给一个const char * ; 这显然是合法的。 在第5行中,我们修改char *指向的内容 – 这应该是合法的。 但是, p1最后指向c ,这是const 。 这是第4行,因为*p2确实是p1 。 这是在第3行build立的,这是一个不允许的forms的分配,这正是为什么行3是不允许的。

而当你的问题被标记为C ++而不是C时,它甚至解释了使用什么const限定符:

(C ++有更复杂的规则来分配const限定的指针,这些指针可以让你进行更多types的赋值,而不会引起警告,但是仍然可以防止无意中修改const值.C ++仍然不允许将char **赋给const char ** ,但它可以让你逃脱分配char **到一个const char * const * 。)

C ++ 11草案标准在4.4节的注释中解释了这一点:

[注意:如果一个程序可以将一个types为T **的指针赋给一个types为const T **的指针(也就是说,如果允许下面的行#1),程序可能会无意中修改一个const对象在线#2)。 例如,

 int main() { const char c = 'c'; char* pc; const char** pcc = &pc; // #1: not allowed *pcc = &c; *pc = 'C'; // #2: modifies a const object } 

– 注意]

一个有趣的相关问题是给定int ** p1和const int ** p2是否p1 == p2格式正确? 。

注意C ++ FAQ也有这个解释,但我更喜欢标准的解释。

随笔记一致的文字如下:

转换可以在多级指针中的第一级以外的级别添加cv限定符,但要遵守以下规则:

如果存在typesT和整数n> 0,则两个指针typesT1和T2是相似的,使得:

T1是cv1,0指向cv1,1的指针,指向cv1的指针,n-1指向cv1的指针,n T

T2是cv2,0指向cv2,1的指针,指向cv2的指针,n-1指向cv2的指针,n T

其中每个cvi,j是const,volatile,const volatile或什么都不是。 在指针types中的第一个之后的cv限定符的n元组,​​例如指针typesT1中的cv1,1,cv1,2,…,cv1,n被称为指针types的cv限定签名。 当且仅当以下条件得到满足时,typesT1的expression式才能转换为typesT2:

  • 指针types是相似的。
  • 对于每个j> 0,如果const是在cv1中,那么j是const在cv2中,j和volatile类似。
  • 如果cv1,j和cv2,j不同,那么const在每个cv2中,k为0 <k <j。

这里有两条规则要注意:

  • 如果T和U是不同的types,则在T*U*之间没有隐式转换。
  • 您可以隐式地将T*T const * 。 (“指向T的指针”可以转换为“指向常量T的指针”)。 在C ++中,如果T也是指针,那么这个规则也可以应用于它(链接)。

举个例子:

char**表示: 指向char的指针的指针

const char**意思是指向指向const char的指针

由于指向char指向const char的指针是不同的types,只有在const中才不同,所以不允许强制转换。 要转换为正确的types应该是const指针char

所以为了保持const正确,你必须从最右边的星号开始添加const关键字。

所以char**可以转换为char * const *并且可以转换为const char * const *

这个链接只是C ++。 在C中,这个链接不起作用,所以在这种语言中,你不能正确地强制转换一个以上的指针级别。