简体   繁体   English

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

[英]Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"

It is legal to convert a pointer-to-non-const to a pointer-to-const.将指向非常量的指针转换为指向常量的指针合法的。

Then why isn't it legal to convert a pointer to pointer to non-const to a pointer to pointer to const ?那么为什么将指向非 const指针的指针转换为指向 const指针的指针是不合法的呢?

Eg, why is the following code illegal:例如,为什么下面的代码是非法的:

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

From the standard:从标准:

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

Ignoring your code and answering the principle of your question, see this entry from the comp.lang.c FAQ: Why can't I pass a char ** to a function which expects a const char **?忽略您的代码并回答您的问题的原则,请参阅 comp.lang.c 常见问题解答中的此条目:为什么我不能将 char ** 传递给需要 const char ** 的函数?

The reason that you cannot assign a char ** value to a const char ** pointer is somewhat obscure.不能将char **值分配给const char **指针的原因有些模糊。 Given that the const qualifier exists at all, the compiler would like to help you keep your promises not to modify const values.鉴于const限定符完全存在,编译器希望帮助您遵守不修改const值的承诺。 That's why you can assign a char * to a const char * , but not the other way around: it's clearly safe to "add" const -ness to a simple pointer, but it would be dangerous to take it away.这就是为什么您可以将char *分配给const char * ,而不是相反:将const -ness“添加”到一个简单的指针显然是安全的,但将其删除会很危险。 However, suppose you performed the following more complicated series of assignments:但是,假设您执行了以下更复杂的一系列作业:

 const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */

In line 3, we assign a char ** to a const char ** .在第 3 行,我们将char **分配给const char ** (The compiler should complain.) In line 4, we assign a const char * to a const char * ; (编译器应该抱怨。)在第 4 行,我们将const char *分配给const char * this is clearly legal.这显然是合法的。 In line 5, we modify what a char * points to--this is supposed to be legal.在第 5 行,我们修改了char *指向的内容——这应该是合法的。 However, p1 ends up pointing to c , which is const .但是, p1最终指向c ,即const This came about in line 4, because *p2 was really p1 .这出现在第 4 行,因为*p2实际上是p1 This was set up in line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.这是在第 3 行中设置的,这是一个被禁止的表单的分配,这正是第 3 行被禁止的原因。

And as your question is tagged C++ and not C, it even explains what const qualifiers to use instead:由于您的问题被标记为 C++ 而不是 C,它甚至解释了要使用的const限定符:

(C++ has more complicated rules for assigning const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modify const values. C++ would still not allow assigning a char ** to a const char ** , but it would let you get away with assigning a char ** to a const char * const * .) (C++ 有更复杂的分配 const 限定指针的规则,这使您可以在不产生警告的情况下进行更多类型的分配,但仍然可以防止无意中尝试修改 const 值。C++ 仍然不允许将char **分配给const char ** ,但它会让您摆脱将char **分配给const char * const * 。)

Just since nobody has posted the solution , here:就因为没有人发布解决方案,这里:

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 for why) http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17为什么)

The C++11 draft standard explains this in a note in section 4.4 which says: C++11 草案标准在第4.4节的注释中解释了这一点,其中说:

[ Note: if a program could assign a pointer of type T** to a pointer of type const T** (that is, if line #1 below were allowed), a program could inadvertently modify a const object (as it is done on line #2). [注意:如果程序可以将 T** 类型的指针分配给 const T** 类型的指针(即,如果允许下面的第 1 行),则程序可能会无意中修改 const 对象(因为它已完成)在第 2 行)。 For example,例如,

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

—end note ] ——尾注]

An interesting related question is Given int **p1 and const int **p2 is p1 == p2 well formed?一个有趣的相关问题是Given int **p1 和 const int **p2 is p1 == p2 wellformed? . .

Note the C++ FAQ also has an explanation for this but I like the explanation from the standard better.请注意, C++ FAQ对此也有解释,但我更喜欢标准中的解释。

The conforming text that goes with the note is as follows:与注释一致的文本如下:

A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules:56转换可以在多级指针的第一个以外的级别添加 cv 限定符,遵循以下规则:56

Two pointer types T1 and T2 are similar if there exists a type T and integer n > 0 such that:如果存在类型 T 和整数 n > 0 使得两个指针类型 T1 和 T2 相似:

T1 is cv1,0 pointer to cv1,1 pointer to · · · cv1,n−1 pointer to cv1,n T T1 是 cv1,0 指向 cv1,1 的指针指向 · · · cv1,n−1 指向 cv1,n 的指针 T

and

T2 is cv2,0 pointer to cv2,1 pointer to · · · cv2,n−1 pointer to cv2,n T T2 是 cv2,0 指向 cv2,1 的指针指向 · · · cv2,n−1 指向 cv2,n 的指针 T

where each cvi,j is const, volatile, const volatile, or nothing.其中每个 cvi,j 是 const、volatile、const volatile 或什么都没有。 The n-tuple of cv-qualifiers after the first in a pointer type, eg, cv1,1, cv1,2, · · · , cv1,n in the pointer type T1, is called the cv-qualification signature of the pointer type.指针类型中第一个之后的 cv 限定符的 n 元组,例如,指针类型 T1 中的 cv1,1, cv1,2, · · · , cv1,n,称为指针类型的 cv 限定签名. An expression of type T1 can be converted to type T2 if and only if the following conditions are satisfied:当且仅当满足以下条件时,类型 T1 的表达式才能转换为类型 T2:

  • the pointer types are similar.指针类型相似。
  • for every j > 0, if const is in cv1,j then const is in cv2,j , and similarly for volatile.对于每个 j > 0,如果 const 在 cv1,j 中,那么 const 在 cv2,j 中,对于 volatile 也是如此。
  • if the cv1,j and cv2,j are different, then const is in every cv2,k for 0 < k < j.如果 cv1,j 和 cv2,j 不同,则 const 在每个 cv2,k 中,因为 0 < k < j。

There are two rules here to note:这里有两条规则需要注意:

  • There are no implicit casts between T* and U* if T and U are different types.如果 T 和 U 是不同的类型,则 T T*U*之间没有隐式转换。
  • You can cast T* to T const * implicitly.您可以隐式地将T*T const * ("pointer to T" can be cast to "pointer to const T"). (“指向 T 的指针”可以转换为“指向 const T 的指针”)。 In C++ if T is also pointer then this rule can be applied to it as well (chaining).在 C++ 中,如果T也是指针,那么这个规则也可以应用于它(链接)。

So for example:例如:

char** means: pointer to pointer to char . char**表示:指向 char 指针的指针

And const char** means: pointer to pointer to const char .const char**意味着:指向 const char 指针的指针

Since pointer to char and pointer to const char are different types that don't differ only in const-ness, so the cast is not allowed.由于指向 char 的指针指向 const char 的指针是不同的类型,仅在常量性方面不同,因此不允许进行强制转换。 The correct type to cast to should be const pointer to char .要强制转换的正确类型应该是指向 char 的 const 指针

So to remain const correct, you must add the const keyword starting from the rightmost asterisk.因此,要保持 const 正确,您必须从最右边的星号开始添加 const 关键字。

So char** can be cast to char * const * and can be cast to const char * const * too.所以char**可以转换为char * const * ,也可以转换为const char * const *

This chaining is C++ only.此链接仅适用于 C++。 In C this chaining doesn't work, so in that language you cannot cast more than one levels of pointers const correctly.在 C 中,这种链接不起作用,因此在该语言中,您不能正确地转换多于一层的指针 const。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM