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
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.
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.
4条答案
按热度按时间iyfamqjs1#
简短回答
你能安全地把
char **
转换成const char**
吗?* 不 。(反正不安全),原因远比你想象的要微妙得多。你能用别的方法处理掉它吗?当然可以。从char*
值中加载const char*
值的数组,然后传递它。(或者更改被调用者原型,但这是欺骗=P)。考虑下面的代码,它基本上完成了您希望的所有操作, 除了 * 调用一个函数。标记的线演示了等效的投射点
字符串
要真正盯着这个看需要一段时间,而且我承认一开始也没有看到。@sheu做了一个坚实的工作,抓住了大约24小时之前,我真的思考了足够长的时间,意识到他沿着是正确的(实际上,我在写这一个之前投票支持这个答案)。然后我认为他错了,就在他认为他的答案不适用的时候。结果我们两个都错了因为他第一次是对的我第二次错了现在...啊。
在VS 2012和VS2010上,标记的行都将标记错误,而不进行强制转换。clang将在C语言中编译它并带有警告,但允许它(我发现这很奇怪)。当然,你必须真正走出你的快乐之地,才能打破它,但它仍然是坏的。
其余的部分是对标识指针类型、它们的常量以及什么等价于什么的谩骂。
"关于指针和常数的长篇大论"
此警告是因为
char **
和const char **
不相等(duh)。正确的做法是,您可以修复原型(被调用方),或者修复调用方(通过加载const char *
数组并传递该数组)。但是你能安全地把第一个转换成第二个吗?嗯......请记住,根据标准
const
会直接转到其 * 左侧 * 的项目。在数据类型的最左边声明它是该语言支持的一个很好的方法,但经常会带来混乱或问题。作为一个经验法则,如果const
出现在decl的最左边,就在类型之前,它适用于data type;不后续指针(如果有)。当它出现在任何东西的右侧时,它应用于紧邻左侧的decl部分,无论它是数据类型部分还是指针部分,但无论如何,它只应用于单个部分。以下是大量示例:
无间接寻址:
型
单间接:
型
双重间接寻址:
型
当然,谁能离开家而不...
型
那么这对你的问题有什么影响呢?在C语言中编译代码时,如果没有强制转换,您将得到编译器警告(如果使用
-Werror
编译,则会得到错误)。在用C++编译时,你只会遇到普通的错误,因为参数签名不匹配。但为什么呢?因为它们没有直接的等价性:
型
使用clang进行编译时,C语言中的确切警告如下所示:
主.c:15:9:将
char **
传递给const char **
类型的参数会丢弃嵌套指针类型中的限定符。另一方面,VS2010和VS 2012都会抛出一个错误:
错误C2440:“正在初始化”:无法从'char**'转换成'const char**'
这看起来很奇怪,但VS实际上更正确(奇迹从未停止)。
这完全说得通。嵌套在类型声明中的事实是,第一个不允许修改最终数据,而第二个 * 允许修改 *。从上面我们知道
char **
和const char **
(即,char const **
),是 * 不 * 相同的。一个的底部是指向const char
的指针,而另一个的底部是指向char
的指针。6vl6ewon2#
这是一个有趣的C语言,如果你认真思考,这是有意义的。
基本上,转换:
字符串
不允许。
你可能会问,为什么?“我在让事情变得更稳定!这显然是一件好事!“
想想看如果允许这样做,那么:
型
你死定了。所以...不:-)
3bygqnnd3#
警告告诉您,您正在调用的函数期望给定的参数为
const char**
,但您正在传递char**
参数。要消除此警告,您可以const char**
const char**
(就像你现在做的那样)char**
zf9nrax14#
我还是觉得这样不对。在示例中:
字符串
打破这一点的线是:
型
因为我们设置了一个非常量的子指针指向一个常量指针。如果是这样:
型
然后
型
是正确的,它不会让你赋值给const char c。
我不认为编译器应该阻止你做一些更常量的东西。