为什么将“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中,这个链接不起作用,所以在这种语言中,你不能正确地强制转换一个以上的指针级别。