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

gre*_*een 31 c gcc

我一直在收到这个警告:

note: expected ‘const char **’ but argument is of type ‘char **’
Run Code Online (Sandbox Code Playgroud)

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

Who*_*aig 50

简答

你可以安全地强制转换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
Run Code Online (Sandbox Code Playgroud)

真的盯着这个需要一段时间,而且我一开始也没看到它.@sheu做了大约24小时才能抓住它,我真的想到它已经足够长时间才能意识到他一直都是对的(我在写这篇文章之前我真的赞成了这个答案).然后我认为他错了,同时他认为他的答案不适用.事实证明我们在那次飞跃中都是错的,因为他第一次是对的,第二次我错了,现在......呃.

在VS2012和VS2010上,标记的行都将标记错误而不进行强制转换.clang会在C中用警告编译它,但是允许它(我发现它很令人惊讶).鉴于,你必须真正走出你快乐的地方来打破它,但它仍然是非常少的.

其余部分是识别指针类型,它们的常量以及等同于什么的指示.


指针与Const的长期诽谤

警告是因为char **而且const char **不等同(duh).为了正确,您可以修复原型(被调用者),或修复调用者(通过加载数组const char *并传递它).但是你可以安全地将第一个到第二个进行类型转换吗?嗯....

请记住,按标准const立即转到左侧的项目.在数据类型的最左侧声明它是语言支持的一种精确性,但通常会引入混淆或问题.作为一个经验法则,如果const出现在紧接类型之前的十进制的最左边,它将应用于数据类型 ; 不是后续指针(如果有的话).当它出现在任何东西的右边时,它适用于立即左侧的decl-part,无论是数据类型部分还是指针部分,无论它只适用于单个部分.

以下是大量样本:

没有间接:

const char ch;    // const character. must be initialized.
char const ch;    // same as above
Run Code Online (Sandbox Code Playgroud)

单方向:

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.
Run Code Online (Sandbox Code Playgroud)

双间接:

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.
Run Code Online (Sandbox Code Playgroud)

当然谁不能离开家...

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
Run Code Online (Sandbox Code Playgroud)

那么这对您的问题有何影响?在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
Run Code Online (Sandbox Code Playgroud)

使用clang进行编译时,C中的确切警告如下:

main.c:15:9:传递char **const char **嵌套指针类型中的discards限定符类型的参数.

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

错误C2440:'初始化':无法从'char**'转换为'const char**'

这看起来很奇怪,但VS实际上更正确(奇迹永远不会停止).

这很有道理.紧跟在类型声明中的事实是,第一个不允许修改最终数据,第二个确实如此.从上面我们知道char **const char **(又名char const **)一样.在一个的底部是指向a的指针const char,而另一个指针指向char.

  • 注意,转换为`char const*const*`是安全的(因为你无法改变它指向的内容).(我已经使用OCaml的类型系统对此进行了验证.)不幸的是,海湾合作委员会人员似乎已经使用大锤方法来禁止所有这些演员阵容,但Clang似乎已经复制了它们. (5认同)

she*_*heu 35

编辑:我甚至回答了错误的问题.我的回答完全无关紧要!请不要理我

编辑2:在绅士提问者澄清他的问题之后,事实证明我的答案实际上是相关的. 这就是生活.

这是一个有趣的C,如果你认真考虑它,这是有道理的.

基本上,转换:

char** ptr;
const char** const_ptr;
const_ptr = ptr;  // <-- BAD!
Run Code Online (Sandbox Code Playgroud)

不被允许.

为什么,你可能会问?"我正在制作更多的东西!这显然是件好事!"


好吧,想一想.如果允许,那么:

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.
Run Code Online (Sandbox Code Playgroud)

BAM你已经死了 所以不行 :-)

  • +1(很久以前,但值得一提)。这就是最终使我的工作成功的答案,如果临时读者还没有这样做,那么它当然值得投票。 (3认同)
  • 如果不相关,您可以删除答案. (2认同)