我收到了这个警告:
note: expected ‘const char **’ but argument is of type ‘char **’
现在,我通过将它们转换为const char **
来传递参数。还有其他方法我可以摆脱它吗?
答案 0 :(得分:46)
简答
您可以安全地将char **
强制转换为const char**
吗?的 没有 即可。 (反正不安全),原因比你想象的要微妙得多。你能用另一种方式摆脱它吗?当然。从const char*
值中加载一组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 **
不等同(duh)。为了正确,您可以修复原型(被调用者),或修复调用者(通过加载const char *
数组并传递它)。但是你可以安全地将第一个到第二个进行类型转换吗?嗯....
请注意,标准const
会立即将项目转到 left 。在数据类型的最左边声明它是语言支持的一种精确性,但经常引入混淆或问题。根据经验法则,如果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中的确切警告为:
另一方面,VS2010和VS2012都抛出错误:main.c:15:9:将
char **
传递给const char **
类型的参数会丢弃嵌套指针类型中的限定符。
错误C2440:'初始化':无法从'char **'转换为'const char **'
看起来很奇怪,但VS实际上更正确(奇迹永远不会停止)。
这很有道理。紧跟在类型声明中的事实是,第一个不允许修改最终数据,第二个执行。从上面我们知道char **
和const char **
(又名。char const **
),不相同。在一个的底部是指向const char
的指针,而另一个指针指向char
。
答案 1 :(得分:31)
编辑:我甚至回答了错误的问题。我的回答完全无关紧要!请忽略我。
编辑2 :在绅士提问者澄清他的问题之后,事实证明我的答案实际上是相关的。 C&#39; est la vie。
这是一个有趣的C,如果你认真考虑它就有意义。
基本上,转换:
char** ptr;
const char** const_ptr;
const_ptr = ptr; // <-- BAD!
是不允许的。
为什么,你可能会问? &#34;我正在制作更多 const的东西!这显然是件好事!&#34;
好吧,想一想。如果允许,那么:
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.
BAM你已经死了。所以......不: - )
答案 2 :(得分:2)
警告告诉您,您正在调用的函数希望给定参数为const char**
,但您传递的是char**
参数。要摆脱这个警告,你可以
const char**
const char**
(就像您目前正在做的那样)char**
答案 3 :(得分:0)
我仍然认为这是不对的。在示例中:
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_ptr = &c;
因为我们将非const子指针设置为const指针。如果是这样:
const char *const *const_ptr
然后
*const_ptr = &c
是正确的,它不会让您分配给const char c。
我认为编译器不会阻止您制作更多常量。