为什么将“指向非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 

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

你不能将char **值赋给const char **指针的原因有点模糊。 鉴于const限定符完全存在,编译器希望帮助您保证不修改const值。 这就是为什么你可以将一个char *分配给一个const char * ,而不是另一种方式:将const -ness“添加”到一个简单的指针显然是安全的,但是把它拿走会很危险。 但是,假设您执行了以下更复杂的分配系列:

 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行中设置的,这是一个不允许的表单的赋值,这正是为什么不允许第3行的原因。

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

(C ++有更复杂的规则来分配const限定指针,这些指针允许你在不引发警告的情况下进行更多种类的赋值,但仍然可以防止无意中尝试修改const值.C ++仍然不允许将char **赋值给const char ** ,但它可以让你逃避将char **分配给const char * const * 。)

只是因为没有人发布解决方案 ,这里:

 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为什么)

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

[注意:如果程序可以将类型为T **的指针分配给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限定符,遵循以下规则:56

如果存在类型T且整数n> 0,则两个指针类型T1和T2类似,使得:

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

T2是cv2,0指向cv2,1指针指向c·2,n-1指向cv2,n T

其中每个cvi,j都是const,volatile,const volatile或什么都不是。 在指针类型中的第一个之后的cv-qualifiers的n元组,​​例如指针类型T1中的cv1,1,cv1,2,…,cv1,n,被称为指针类型的cv-限定签名。 当且仅当满足以下条件时,类型T1的表达式才能转换为T2类型:

  • 指针类型类似。
  • 对于每个j> 0,如果const在cv1中,j则const在cv2,j中,并且类似于volatile。
  • 如果cv1,j和cv2,j不同,则const在每个cv2中,k为0

这里有两条规则需要注意:

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

例如:

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

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

由于指向char的 指针指向const char的指针是不同的类型,它们仅在const-ness中不同,因此不允许转换。 要转换为的正确类型应该是指向char的const指针

因此,要保持const正确,必须从最右边的星号开始添加const关键字。

因此char**可以转换为char * const * ,也可以转换为const char * const *

这种链接只是C ++。 在C中,这种链接不起作用,因此在该语言中,您无法正确地转换多个指针级别。