为什么将"指向非const的指针"转换为"指向const的指针"是不合法的

ash*_*ony 35 c++ pointers const const-correctness

合法的指针到非const转换为指针到常量.

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

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

char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char **ps = a; // error!
Run Code Online (Sandbox Code Playgroud)

APr*_*mer 35

从标准:

const char c = 'c';
char* pc;
const char** pcc = &pc;   // not allowed
*pcc = &c;
*pc = 'C';                // would allow to modify a const object
Run Code Online (Sandbox Code Playgroud)


jam*_*lin 20

忽略你的代码并回答你的问题的原则,请参阅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 */
Run Code Online (Sandbox Code Playgroud)

在第3行中,我们将a分配char **给a const char **.(编译器应该抱怨.)在第4行,我们分配a const char *到a const char *; 这显然是合法的.在第5行,我们修改了char *要点 - 这应该是合法的.然而,p1最终指向c,这是const.这是第4行,因为*p2真的p1.这是在第3行中设置的,它是一个不允许的表单的赋值,这正是为什么不允许第3行的原因.

由于你的问题被标记为C++而不是C,它甚至可以解释const使用哪些限定词:

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

  • 从更着名的C++常见问题解答:http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17 (3认同)

Pot*_*ter 11

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

char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!
Run Code Online (Sandbox Code Playgroud)

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

  • 应该注意的是,它不适用于C,只适用于C++. (6认同)
  • 问题没有标记[tag:C].downvote还有其他原因吗? (5认同)

Sha*_*our 10

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
}
Run Code Online (Sandbox Code Playgroud)

- 尾注]

一个有趣的相关问题是给定int**p1和const int**p2是p1 == p2是否形成良好?.

注意C++ FAQ也有解释,但我更喜欢标准中的解释.

与说明一致的符合文本如下:

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

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

T1是cv1,0指针指向cv1,1指针指向cv1,n指针指向cv1,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 <k <j.


Cal*_*ius 6

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

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

例如:

char**意思是:指向char的指针.

并且const char**意味着:指向const char的指针.

因为指向char的指针指向const char的指针是不同的类型,只有const-ness不同,所以不允许转换.要转换为的正确类型应该是指向char的const指针.

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

所以char**可以演员char * const *也可以演员const char * const *.

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