我一直收到这个警告:
note: expected ‘const char **’ but argument is of type ‘char **’
现在,我通过将参数转换为const char **
. 有没有其他方法可以摆脱它?
简答
你可以安全地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
,它会立即转到其左侧的项目。在数据类型的最左侧声明它是该语言支持的一个优点,但通常会带来混乱或问题。根据经验,如果const
出现在 decl 的最左侧紧挨在类型之前,它适用于数据类型;不是后续指针(如果有)。当它出现在任何东西的右侧时,它适用于立即左侧的 decl 部分,无论是数据类型部分还是指针部分,但无论如何它只适用于单个部分。
大量样本如下:
无间接:
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 **
(aka. char const **
), 是不一样的。一个的底部是指向 a 的指针const char
,而另一个是指向 的指针char
。
编辑:我什至回答了错误的问题。我的回答完全无关紧要!请忽略我。
编辑2:在绅士提问者澄清他的问题后,事实证明我的回答实际上是相关的。 这就是生活。
这是 C 的一个有趣的部分,如果你足够认真地思考它,这是有道理的。
基本上,转换:
char** ptr;
const char** const_ptr;
const_ptr = ptr; // <-- BAD!
不允许。
为什么,你可能会问?“我让事情变得更加const!这显然是件好事!”
好吧,想想这个。如果允许,那么:
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你死了。所以不行 :-)
警告告诉您,您正在调用的函数需要给定的参数,const char**
但您正在传递一个char**
参数。要摆脱这个警告,你可以
const char**
const char**
(就像您目前正在做的那样)char**
我仍然认为这是不对的。在示例中:
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。
我不认为编译器应该阻止你做更多的事情。