编译器抱怨的原因是第一个const
in f
的声明。
尝试使用
void f(struct_type *const data[], unsigned n);
/*...*/
f( v, n );
并且您不会收到相同的警告。或者,您可以投射v
你打电话时f
void f(const struct_type *const data[], unsigned n);
/*...*/
f( (const struct_type * const *) v, n );
这有点违反直觉,但在 C 中,你不能传递pointer-to-pointer-to-nonconst
for a pointer-to-pointer-to-const
。他们破例允许你通过pointer-to-nonconst
for a pointer-to-const
.
这是一个常见问题解答“为什么我不能通过char **到一个期望的函数const char **?":
您可以使用pointer-to-T
(对于任何类型T
)其中一个pointer-to-const-T
是期待。但是,允许限定指针类型中存在轻微不匹配的规则(显式例外)不会递归应用,而仅在顶层应用。 (const char **
is pointer-to-pointer-to-const-char
,因此该例外情况不适用。)
您无法分配的原因char **
值对一个const char **
指针有些晦涩。鉴于const
限定符确实存在,编译器希望帮助您信守不修改的承诺const
价值观。这就是为什么你可以分配一个char *
to a const char *
,但反之则不然:这显然是安全的add const
-ness 是一个简单的指针,但是把它拿走是危险的。但是,假设您执行了以下一系列更复杂的作业:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
在第 3 行中,我们分配了一个char **
to a const char **
。 (编译器应该抱怨。)在第 4 行中,我们分配了一个const char *
to a const char *
;这显然是合法的。在第 5 行中,我们修改了char *
指向——这应该是合法的。然而,p1 最终指向 c,即const
。这发生在第 4 行,因为 *p2 实际上是 p1。这是在第 3 行中设置的,这是不允许的表单赋值,这正是第 3 行不允许的原因。
分配一个char **
to a const char **
(如第 3 行和原来的问题)并不是立即危险的。但它造成了一种情况,即 p2 的承诺——最终指向的值不会被修改——无法兑现。
(C++ 有更复杂的赋值规则const
- 限定指针,允许您进行更多类型的分配而不会产生警告,但仍然可以防止无意的修改尝试const
价值观。 C++ 仍然不允许分配char **
to a const char **
,但它会让你逃脱分配char **
to a const char * const
*.)
在 C 中,如果必须分配或传递在第一级间接寻址之外具有限定符不匹配的指针,则必须使用显式强制转换(例如 (const char **
)在这种情况下),尽管与往常一样,对这样的强制转换的需要可能表明强制转换并不能真正解决更深层次的问题。
参考文献: ISO Sec. 6.1.2.6,秒。 6.3.16.1,秒。 6.5.3
H&S Sec. 7.9.1 第 221-2 页