【问题标题】:Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"为什么将“指向非 const 的指针”转换为“指向 const 的指针”是不合法的
【发布时间】:2011-01-14 07:44:39
【问题描述】:

将指向非常量的指针转换为指向常数的指针合法的。

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

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

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

【问题讨论】:

  • 我建议你将“a”定义为“char **”,你的例子会更清晰,没有不必要的数组。
  • 是的,但是当 a 是 char** 时,他的问题也适用。
  • 下面的解释其实还不错。
  • @MaxShawabkeh 它衰减到char**,没有const
  • 看起来我回答的一个问题已与这个问题合并,请参阅my answer below,它现在是您问题的一部分。

标签: c++ pointers constants const-correctness


【解决方案1】:

来自标准:

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

【讨论】:

    【解决方案2】:

    忽略您的代码并回答您问题的原则,请参阅 comp.lang.c 常见问题解答中的以下条目: Why can't I pass a char ** to a function which expects a 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 *。)

    【讨论】:

    【解决方案3】:

    由于没有人发布解决方案,这里:

    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,只适用于C++。
    • 该问题未标记为c。否决票还有其他原因吗?
    【解决方案4】:

    C++11 draft standard4.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
    }
    

    ——尾注]

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

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

    附注的符合性文字如下:

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

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

    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 或什么都没有。这 指针类型中第一个之后的 cv 限定符的 n 元组,例如, cv1,1, cv1,2,···, cv1,n 在指针类型 T1 中,称为 指针类型的 cv 限定签名。类型的表达 当且仅当满足以下条件时,T1 才能转换为 T2 类型 满意:

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

    【讨论】:

    • 非常感谢。看了几遍你的回答我终于明白了!
    • @AntonTugolukov 看起来您的问题已与当前问题合并
    【解决方案5】:

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

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

    例如:

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

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

    由于 pointer to charpointer to const char 是不同的类型,它们的区别仅在于 const 性,因此不允许进行强制转换。要转换为的正确类型应该是 const pointer to char

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

    所以char** 可以转换为char * const *,也可以转换为const char * const *

    此链接仅适用于 C++。在 C 中,这种链接不起作用,因此在该语言中,您不能正确地转换多于一级的指针 const。

    【讨论】:

      猜你喜欢
      • 2017-05-15
      • 2015-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-23
      相关资源
      最近更新 更多