此问题已在此处得到解决。
建议的重复和当前给出的答案没有解决为什么首先给出的示例没有问题。主要是为什么不推理:
“
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("%d\n", a);
}
void f_ptr_a_type1 (int const * ptr_a){
/*
* Can do this:
* ptr_a’ = 0x3;
* which make dereferencig to a impossible.
* printf("%d\n", * 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** 不同,你不能安全地转换它
我的问题是为什么函数突然关心?
这里没有抱怨
int
不是int 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);
但是突然它开始抱怨双指针的情况。
寻找使用此术语和示例的解释?
为什么函数突然开始担心 write 超出她范围的权限?
从例如转换
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!
}
如果调用
char **
时从 const char **
到 foo()
的转换是隐式的,那么您将有一种隐式转换 const
的方法。
该语言不允许不安全的转换,即将指向
const
对象的指针转换为指向非const
对象的指针。
它不关心安全转换,即那些你应用比传递的东西真正具有的更严格的
const
资格的转换。例如,如果对象确实是可写的,但您将其传递给只需要读取它的函数,则没有必要抱怨这一点。
你的例子显示了后者:
f_ptr_a_type1(&a);
这表示'对我声明为非
const
的这个int
进行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("%d\n", ** ptr_ptr_b); // Look at me, I've just changed the value of const ** int.
** ptr_ptr_a = 15;
printf("%d\n", ** 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("%d\n", ** 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 **
是指向不同事物的指针。