简答
你能安全地将char ** 转换为const char** 吗? 没有。 (无论如何都不安全),原因比你想象的要微妙得多。你能用另一种方式摆脱它吗?当然。从您的 char* 值中加载 const char* 值数组,然后将其传递。 (或更改被调用者原型,但那是作弊=P)。
考虑下面的代码,它基本上做了你希望除了调用一个函数的所有事情。标记的线表示等效的投射点
const char *s = "Test";
char *p = NULL;
char **pp = &p; // Put address of our pointer in our pointer-to-pointer.
const char **cpp = pp; // Here: assigning char** to const char**
*cpp = s; // perfectly legal; pp and s both finish "char const"
*p = 0; // ru ro raggy
真正盯着它需要一段时间,诚然我一开始也没有看到它。 @sheu 在我真正思考足够长的时间以意识到他一直都是对的之前大约 24 小时做了一个扎实的工作(实际上我在写这个答案之前赞成这个答案)。然后我认为他错了,同时他认为他的答案不适用。结果我们在那个飞跃中都错了,因为他第一次是对的,我第二次错了,现在......呃。
在 VS2012 和 VS2010 上,标记的行都会在没有强制转换的情况下标记错误。 clang 将在 C 中使用警告编译它,但允许它(我发现这令人惊讶)。鉴于,你确实必须真正走出你快乐的地方才能打破它,但它仍然是破碎的。
剩下的部分是关于识别指针类型、它们的常量以及什么等价于什么的谩骂。
指针和常量的长篇大论
警告是因为char ** 和const char ** 不等价(呃)。正确地说,您可以修复原型(被调用者),或修复调用者(通过加载 const char * 数组并传递它)。但是你能安全地将第一个转换为第二个吗?嗯……
请记住,按照标准,const 会立即转到其左侧的项目。在数据类型的最左侧声明它是该语言支持的一个优点,但通常会带来混乱或问题。作为一个经验法则,如果const 出现在紧靠类型之前的 decl 的最左侧,则它适用于数据 type; 不是后续指针(如果有)。当它出现在任何东西的右侧时,它适用于立即左侧的decl-part,无论是数据类型部分还是指针部分,但不管它只是什么适用于单个部分。
大量样本如下:
无间接性:
const char ch; // const character. must be initialized.
char const ch; // same as above
单间接:
char *p; // p is mutable, *p is mutable
const char *p; // p is mutable, *p is const
char const *p; // same as above.
char *const p; // p is const, *p is mutable, must be initialized.
char const *const p; // p is const, *p is const, must be initialized.
双重间接:
char **p; // ptr-to-ptr-to-char
// p, *p, and **p are ALL mutable
const char **p; // ptr-to-ptr-to-const-char
// p and *p are mutable, **p is const
char const **p; // same as above
char *const *p; // ptr-to-const-ptr-to-char
// p is mutable, *p is const, **p is mutable.
char **const p; // const-ptr-to-ptr-to-char
// p is const, *p is mutable, **p is mutable.
// must be initialized.
const char **const p; // const-ptr-to-ptr-to-const-char
// p is const, *p is mutable, **p is const.
// must be initialized.
char const **const p; // same as above
char const *const *p; // ptr-to-const-ptr-to-const-char
// p is mutable, *p is const, **p is const.
const char *const *p; // same as above.
char *const *const p; // const-ptr-to-const-ptr-to-char
// p is const, *p is const, **p is mutable.
// must be initialized.
当然还有谁可以离开家而不...
char const *const *const p; // const-ptr-to-const-ptr-to-const-char
// everything is const.
// must be initialized.
const char *const *const p; // same as above
那么这对您的问题有何影响?在 C 中编译该代码时,如果没有强制转换,您将收到编译器警告(如果使用 -Werror 编译,则会出现错误)。在 C++ 中编译时,您将只是简单的错误,因为参数签名不匹配。但为什么呢?
因为这些没有直接等价性:
const char **p; // ptr-to-ptr-to-const-char
// p and *p are mutable **p is const
char **p; // ptr-to-ptr-to-char
// p, *p, and **p are all mutable
使用 clang 编译时,C 中的确切警告如下:
main.c:15:9:将char ** 传递给const char ** 类型的参数会丢弃嵌套指针类型中的限定符。
VS2010 和 VS2012 都在另一方面,抛出一个错误:
错误 C2440:“正在初始化”:无法从“char **”转换为“const char **”
看起来很奇怪,但实际上 VS 更正确(奇迹永远不会停止)。
这很有意义。在类型声明中隐藏的事实是,其中第一个不允许修改最终数据,第二个允许。从上面我们知道char ** 和const char **(又名char const **)是不相同的。一个的底部是指向const char 的指针,而另一个是指向char 的指针。