首页 > 解决方案 > 指向指针的只读指针

问题描述

在 C 中,const char *p有时称为“只读”指针:指向常量对象(在本例中为 a char)的指针。

似乎要么

  1. const char **p
  2. const char *const *p

将是指向指针的只读指针的等效声明,具体取决于有多少间接级别是不可变的

但是,编译器(gcc、clang)会生成警告。

我的问题:如何将指向char **p函数的指针(如)作为“只读”指针传递给函数而不产生警告?如果需要显式转换,为什么在char **pand not的情况下char *p

更多细节

这是我要实现的目标的具体示例。

只读指针

此代码视为char *ptr只读指针。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void readonly(const char *ptr)
{
    // ... do something with ptr ...

    // but modifying the object it points to is forbidden
    // *ptr = 'j';  // error: read-only variable is not assignable
}

int main(void)
{
    char *ptr =  malloc(12*sizeof(char));
    strcpy(ptr, "hello world");

    printf("before: %s\n", ptr);
    readonly(ptr);
    printf("after: %s\n", ptr);

    free(ptr);
    return 0;
}

限定符const添加到函数调用中,没有任何抱怨。

指向指针的只读指针

我希望使用指向指针的指针应该可以进行类似的函数调用。

void readonly(const char *const *ptr)
{
    //  ... do something with ptr ...

    // but modifying the object it points to is forbidden
    // **ptr = 'j';
}

int main(void)
{
    char **ptr;

    ptr = (char **) malloc(2*sizeof(char *));

    ptr[0] = malloc(14*sizeof(char));
    strcpy(ptr[0], "hello world 0");

    ptr[1] = malloc(14*sizeof(char));
    strcpy(ptr[1], "hello world 1");

    printf("before: %s %s\n", ptr[0], ptr[1]);
    readonly(ptr);
    printf("after: %s %s\n", ptr[0], ptr[1]);

    free(ptr[1]);
    free(ptr[0]);
    free(ptr);
    return 0;
}

clang 编译器(6.0.0 版)给出了最易读的警告。

warning: passing 'char **' to parameter of type
    'const char *const *' discards qualifiers in nested pointer types
    [-Wincompatible-pointer-types-discards-qualifiers]
    readonly(ptr);
         ^~~
note: passing argument to parameter 'ptr' here
    void readonly(const char *const *ptr)

但是 gcc (8.1.1) 也给出了警告。

旁白:当我尝试添加限定符时,clang 说通过char ** 丢弃限定符似乎很奇怪?

问题

  1. 如何将指向char **p函数的指针(如 )作为“只读”指针传递而不产生警告?

  2. 如果需要显式转换,为什么在char **pand not的情况下char *p

标签: cpointers

解决方案


您的函数readonly(const char *ptr)承诺它不会触及指针后面的内容。
这就是调用者可以信任地传递指向 const 内存区域的指针(传递 a const char *ptr)的原因。
当然,将非常量传递char *ptr给该函数也没有问题,因为您的函数承诺比需要的安全性更高。这就是为什么编译器会在没有任何警告或注释的情况下遵循您的意愿。

然而,这种自动性只适用于第一个间接级别。

标准在 6.5.16.1 中声明对于赋值,“两个操作数都是指向兼容类型的合格或不合格版本的指针,左侧指向的类型具有右侧指向的类型的所有限定符
最后一部分of the sentence 意味着在指向的类型中添加限定符是没有问题的。
第一部分声称“兼容”类型。并且(我认为)6.7.3 (11) 确实为合格类型描述了这一点:“对于两个兼容的合格类型,两者都应具有兼容类型的相同合格版本。

阅读本文,您指向的类型不被认为是兼容的(即使可以将一个分配给另一个)。

因此,我会说关于丢弃限定符的 clang 警告有点误导,但它指的是非相同限定的指向类型。


推荐阅读