C语言 常量导致不兼容的指针类型.为什么只用于双指针?



这个问题已经在这里解决了。

建议的重复项和当前给出的答案并没有解决为什么首先给出的示例没有问题。主要是为什么推理不:

"const int ** is a pointer to const int *这和int*是不一样的">

同时申请:

"const int * is a pointer to const int这和刚刚int是不一样的">


我从不同的角度接近它,希望得到另一种解释。

包含示例的代码。

#include <stdio.h>
void f_a (int const a){
/*
*  Can't do:
*      a = 3;  //error: assignment of read-only parameter ‘a’
*
* Explanation: I can't change the value of a in the scope of the function due to the const
*/
printf("%dn", a);
}
void f_ptr_a_type1 (int const * ptr_a){
/*
* Can do this:
*     ptr_a’ = 0x3;
* which make dereferencig to a impossible.
*     printf("%dn", * ptr_a’);  -> segfault
* But const won't forbid it.
*
*  Can't do:
*      *ptr_a’ = 3;  //error: assignment of read-only parameter ‘* ptr_a’
*
* Explanation: I can't change the value of a by pointer dereferencing and addignment due to the int const
*/
}
void f_ptr_a_type2 (int * const ptr_a){
/*
* Can do this:
*     *a = 3;
*
*  Can't do:
*      ptr_a = 3;  //error: assignment of read-only parameter ‘ptr_a’
*
* Explanation: I can't change the value because the const is protecting the value of the pointer in the funcion scope
*/
}
void f_ptr_ptr_a (int const ** ptr_ptr_a){
/*
* Can do this:
*     ptr_ptr_a = 3;
*     * ptr_ptr_a = 0x3;
*
*  Can't do:
*      ** ptr_ptr_a = 0x3;  //error: assignment of read-only parameter ‘**ptr_a’
*
* Explanation: Makes sense. Just follows the pattern from previous functions.
*/
}
int main()
{
int a = 7;
f_a(a);
int * ptr_a = &a;
f_ptr_a_type1(&a);
f_ptr_a_type2(&a);
int ** ptr_ptr_a = &ptr_a;
f_ptr_ptr_a(ptr_ptr_a);  //warning: passing argument 1 of ‘f_ptr_ptr_a’ from incompatible pointer type [-Wincompatible-pointer-types]
}

被广泛接受的答案是这样的:

int ** 与 const int** 不同,您无法安全地强制转换它

我的问题是为什么函数突然关心

它没有在这里抱怨intint const

int a = 7;
f_a(a);

它在这里没有抱怨,因为int *既不int const *也不int * const

int * ptr_a = &a;
f_ptr_a_type1(&a);
f_ptr_a_type2(&a);

但突然间,它开始在双指针的情况下抱怨。

  • 寻找使用此术语和示例的解释?

  • 为什么函数突然开始担心写入 权限超出她范围的内容?

例如char *const char *始终是安全的。通过const char *,指向的数据无法修改,仅此而已。

另一方面,从char **const char **的转换可能是不安全的,因此不允许隐式进行。与其解释它,不如考虑以下代码:

void foo(const char **bar)
{
const char *str = "test string";
*bar = str; // perfectly legal
}
int main(void)
{
char *teststr[] = {0};
foo((const char **)teststr);
// now teststr points to a `const char *`!
*teststr[0] = 'x'; // <- attempt to modify read-only memory
//    ok in this line, there's no const qualifier on teststr!
}

如果在调用foo()时从char **const char **的转换是隐式的,您将有一种隐式方式将const转换出去。

该语言不允许不安全的转换,即将指针投射到const对象到指向非const对象的指针。

它不关心安全转换,即那些你应用比通过的东西更严格的const资格的转换。例如,如果对象确实是可写的,但您将它传递给只需要读取它的函数,则抱怨这一点是没有意义的。

您的示例显示了后者:

f_ptr_a_type1(&a);

这说'对我宣布为非constint采取const的看法">

f_ptr_a_type2(&a);

这只是说'这是一个指向同一个非const int的指针,你将获取该指针的副本,该指针将const在函数体中(指针,而不是int)">

至于错误的那个:

f_ptr_ptr_a(ptr_ptr_a);

这是由于一些程序员所说的:引用的类型是不同的,虽然C/C++将允许传递指向指针的指针到const,其中需要指向非const的指针,但它不会通过多个级别的指针"级联"该转换,因为这可能是不安全的,正如Felix Palmen所说明的那样。

为什么函数突然开始担心写入权限 超出她范围的事情?

这并不是说抱怨来自函数参数的观点。该参数的行为将符合预期 函数作用域,并且不受变量进入函数作用域之前发生的情况的影响。

void f_ptr_ptr_a (int const ** ptr_ptr_a){
/*
*  Can't do:
*      ** ptr_ptr_a = 3;  //error: assignment of read-only parameter ‘**ptr_a’
*/
}

int const ** ptr_ptr_a进入由值复制的函数范围,不允许更改** ptr_ptr_a。该错误与 变量被值复制后是什么样子的。

该错误是由于函数调用期间发生隐式强制转换而出现的。剖析我们得到f_ptr_ptr_a(ptr_ptr_a);调用:

int const ** ptr_ptr_x = ptr_ptr_a;     //This line causes the warning
f_ptr_ptr_a(ptr_ptr_x);

寻找使用此术语和示例的解释?

现在让我们将示例剥离到最基本的内容。

int main()
{
int a = 3;
int * ptr_a = &a;
int ** ptr_ptr_a = &ptr_a;        // I promise here **ptr_ptr_a will always be the same

int const b = 5;
int const * ptr_b = &b;
int const ** ptr_ptr_b = &ptr_b;
ptr_ptr_b = ptr_ptr_a;                  // Warning here: -Wincompatible-pointer-types-discards-qualifiers
printf("%dn", ** ptr_ptr_b);           // Look at me, I've just changed the value of const ** int.
** ptr_ptr_a = 15;
printf("%dn", ** ptr_ptr_b);            // I did it again.
}

编译器警告我们,因为隐式强制转换。

int main()
{
int const a = 3;
int const * ptr_a = &a;
int const ** ptr_ptr_a = &ptr_a;        // I promise here **ptr_ptr_a will always be the same
int const b = 5;
int const * ptr_b = &b;
int const ** ptr_ptr_b = &ptr_b;
ptr_ptr_b = ptr_ptr_a;
printf("%dn", ** ptr_ptr_b);           // Look at me, I've just changed the value of const ** int.
// And there were no warnings at all. Har har har har!
}

我可以从这个问题中得出一个结论,从目前的角度来看,它引入了不必要的复杂性。

请始终记住,通过取消引用进行访问与直接访问不是一回事

我们在这里看到了它。const限定符实际上是在做它应该做的事情,防止我们通过取消引用机制更改** ptr_ptr_b。 当然,我们已经设法显然更改了只读值,但这只是因为我们对可怜的const要求很多。

从这里开始的Sheu回答的另一个例子

const char c = 'A';
char* ptr;
const char** const_ptr = &ptr;  // <-- ILLEGAL, but what if this were legal?
*const_ptr = &c;
*ptr = 'B';  // <- you just assigned to "const char c" above.
printf("%c n", c);
printf("%c n", *ptr);

当你说you just assigned to "const char c" above时,这不是真的,这只是引用抽象失控。

让我们稍微分解一下:

  • const int **是指向const int *的指针。

  • int **是指向int *的指针。

换句话说,const int **是指向一个事物的指针,而int **是指向不同事物的指针。

最新更新