首页 > 解决方案 > 当我使用 const 作为指针时,我收到不兼容的指针类型警告

问题描述

编写以下代码时:

#include <general.dep>

typedef struct {
} obj;

int f1(obj **o) {
    return 0;
}

int f2(obj *const *o) {
    return 0;
}

int f3(const obj **o) {
    return 0;
}

int f4(const obj *const *o) {
    return 0;
}

int main() {
    obj **o;
    f1(o);
    f2(o);
    f3(o);
    f4(o);
    return 0;
}

我收到以下警告消息:

gcc t1.c -I/home/hamidi/code/lib/general/inc -fmax-errors=1 -lgeneral -llzma -pthread -o t1
t1.c: In function ‘main’:
t1.c:26:6: warning: passing argument 1 of ‘f3’ from incompatible pointer type [-Wincompatible-pointer-types]
26 |   f3(o);
   |      ^
   |      |
   |      obj ** {aka struct <anonymous> **}
t1.c:14:20: note: expected ‘const obj **’ {aka ‘const struct <anonymous> **’} but argument is of type ‘obj **’ {aka ‘struct <anonymous> **’}
14 | int f3(const obj **o) {
   |        ~~~~~~~~~~~~^
t1.c:27:6: warning: passing argument 1 of ‘f4’ from incompatible pointer type [-Wincompatible-pointer-types]
27 |   f4(o);
   |      ^
   |      |
   |      obj ** {aka struct <anonymous> **}
t1.c:18:26: note: expected ‘const obj * const*’ {aka ‘const struct <anonymous> * const*’} but argument is of type ‘obj **’ {aka ‘struct <anonymous> **’}
18 | int f4(const obj *const *o) {
   |        ~~~~~~~~~~~~~~~~~~^

如何解决这些警告问题?

更新

我标记了发出以下警告的函数:

void f0(obj **ppo) {}
void f1(const obj **ppo) {}  //
void f2(obj const **ppo) {}  //
void f3(obj *const *ppo) {}
void f4(obj **const ppo) {}
void f5(const obj const **ppo) {}  //
void f6(const obj *const *ppo) {}  //
void f7(const obj **const ppo) {}  //
void f8(obj const *const *ppo) {}  //
void f9(obj const **const ppo) {}  //
void fa(obj *const *const ppo) {}
void fb(const obj const *const *ppo) {}        //
void fc(const obj const **const ppo) {}        //
void fd(const obj *const *const ppo) {}        //
void fe(obj const *const *const ppo) {}        //
void ff(const obj const *const *const ppo) {}  //

我不确定哪些是等价的。似乎 f2 和 f3 不同,因为 f2 发出警告而 f3 没有。那么,我们可以说obj const *与 不同obj *const吗?

更新 2

obj 的 const 可以放在它之前或之后,但对于指针,它应该放在它们之后。所以,让我们把两者都放在 const 之后。现在我的问题是在以下代码中:

void f(int const* const* ppi) {
    //**ppi = **ppi;
    //*ppi = *ppi;
    ppi = ppi;
}

void g(int const* pi) {
    //*pi = *pi;
    pi = pi;
}

int main() {
    int i, *pi = &i, **ppi = &pi;
    f(ppi);
    g(pi);
    return 0;
}

我调用了两个函数,f & g。两个函数原型都表明参数的内容没有改变。g 不会改变指针的内容, f 不会改变指针的内容和指针内容指向的内容。

现在我的问题是,为什么编译器仅在调用 f 而不是 g 时才发出此警告?!如果 f 要说我不会更改指针的内容和它指向的内容,那么它的原型应该是什么?

warning: passing argument 1 of ‘f’ from incompatible pointer type [-Wincompatible-pointer-types]
   16 |   f(ppi);
      |     ^~~
      |     |
      |     int **
t2.c:3:26: note: expected ‘const int * const*’ but argument is of type ‘int **’
    3 | void f(int const* const* ppi) {
      |        ~~~~~~~~~~~~~~~~~~^~~

标签: c

解决方案


更新:此答案已更新以修复评论中讨论的错误

与指针一起使用时的工作方式const有点微妙。

const obj*andobj const*表示指针指向 const obj 类型,而obj* const表示指针是 const 并指向非 const obj 类型。

使用这个逻辑const obj**等价于obj const**which 是一个非常量指针,它指向一个指向一个 const obj 的非常量指针,而obj* const*一个非常量指针指向一个指向一个非常量 obj 的 const 指针。Andobj** const是一个指向非 const 指针的 const 指针,该指针指向一个非 const obj。

C++ 可以将非常量类型隐式转换为 const 类型。f2(o)您可以在隐式转换obj*为的调用中看到这一点obj* const

另一方面,C++ 在隐式转换多级指针时必须小心。如果 C++ 允许obj**隐式转换为const obj**以下代码,则允许:

const int x = 0;             //x should never be modified
int* xPtr;
const int** xPtrPtr = &xPtr; //would be legal if C++ allowed int** -> const int** conversion
*xPtrPtr = &x;
*xPtr = 1;                   //This changes the value of x!

出于这个原因,GCC 在调用时会发出错误,f3(o)因为它隐式地将 a 转换obj**const obj**.

您可以在此处阅读多级指针转换的完整要求

我不知道你需要你的代码做什么,但如果你要修改底层objobj*inf3你应该将它的参数更改为obj** const. 如果您不想修改底层obj但修改obj*您应该改为使用obj const**作为参数。如果你不想修改或者objobj*应该使用obj const* const*


推荐阅读