2010-02-08 179 views
29

合法将指针指向非常量转换为指针指向常量,常量。为什么将“指针指向非常量”转换为“指向常量指针的指针”

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

例如,为什么下面的代码不合法​​:

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

我建议你定义的“A”为“字符**”,你的例子会更清楚没有不必要的阵列。 – Manuel 2010-02-08 10:39:07

+0

'* a [MAX]'不会导致'char **'但实际上'char ** const'。另外:http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17。 – 2010-02-08 10:45:13

+1

是的,但是当他是char **时,他的问题也适用。 – Manuel 2010-02-08 10:48:24

回答

34

从标准:

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

忽略你的代码,并回答你的问题的原则,看到从comp.lang此条.c FAQ: Why can't I pass a char ** to a function which expects a const 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 *分配给const char *;这显然是合法的。在第5行中,我们修改了char *指向的内容 - 这应该是合法的。但是,p1最终指向c,即const。这是第4行,因为*p2真的是p1。这是在第3行建立的,这是一个不允许的表单的分配,这正是为什么第3行不被允许。

至于你的问题被标记C++而不是C,它甚至解释了什么是const预选赛改用:

(C++有分配const限定的指针它让你赚更多更复杂的规则但仍然可以防止无意中尝试修改常量值,C++仍然不允许将char **分配给const char **,但是它可以让您将char **分配给const char * const *。)

+3

并从更为人熟知的C++常见问题解答:http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17 – Potatoswatter 2010-02-08 11:10:15

6

这里有两个规则要注意:

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

因此,例如:

char**指:指针字符指针

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

由于字符指针指针为const char是不同类型的不只有常量性不同,因此中投是不允许的。要转换为的正确类型应该是const指向字符的指针。

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

因此char**可以投到char * const *,也可以投到const char * const *

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

8

C++11 draft standard解释了这个在部分4.4一张纸条,上面说:

[注:如果一个程序能型T **的指针赋给类型为const T **的指针 (即如果允许以下第1行),程序 可能会无意中修改常量对象(如第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 
} 

就要收注]

一个有趣的相关的问题是Given int **p1 and const int **p2 is p1 == p2 well formed?

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

是用音符去的符合文本如下:

A转换可以在 多层次的三分球比第一其他级别,必须符合以下规则添加CV-预选赛:56

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

T1是cv1,0指针cv1,1指针···CV1,n-1个指针CV1,正 Ť

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

其中每个cvi,j是const,volatile,const volatile或nothing。指针类型T1中的第一个指针类型(例如, cv1,1,cv1,2,...,cv1,n)之后的cv-限定符的n元组被称为 cv限定符指针类型。 类型的表达式T1可以被转换为类型T2当且仅当下列条件 被满足:

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

非常感谢。几次阅读你的答案后,我终于明白了! – Anton 2015-03-24 18:53:26

+0

@AntonTugolukov看起来像你问题被合并w /这个当前之一 – 2016-07-25 17:22:28