为什么将char **作为const char **传递会产生警告?

时间:2013-01-28 13:14:26

标签: c gcc

我收到了这个警告:

note: expected ‘const char **’ but argument is of type ‘char **’

现在,我通过将它们转换为const char **来传递参数。还有其他方法我可以摆脱它吗?

4 个答案:

答案 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中的确切警告为:

  

main.c:15:9:将char **传递给const char **类型的参数会丢弃嵌套指针类型中的限定符。

另一方面,VS2010和VS2012都抛出错误:

  

错误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。

我认为编译器不会阻止您制作更多常量。