为什么将 char** 作为 const char** 传递会产生警告? [英] Why does passing char** as const char** generate a warning?

查看:43
本文介绍了为什么将 char** 作为 const char** 传递会产生警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直收到此警告:

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

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

For now, I'm passing the arguments by casting them to const char **. Is there any other way I can get rid of it?

推荐答案

简短回答

你能安全地将 char ** 转换为 const char** 吗?没有.(无论如何都不安全),原因比您想象的要微妙得多.你能用另一种方式摆脱它吗?当然.从您的 char* 值中加载 const char* 值的数组并传递它.(或更改被调用者原型,但那是作弊=P).

Can you safely typecast char ** to const char**? No. (Not safely anyway), and the reason is far more subtle than you may think. Can you get rid of it another way? Sure. Load an array of const char* values from your char* values and pass that instead. (or change the callee prototype, but thats cheating =P).

考虑下面的代码,它基本上完成了您希望除了调用一个函数的所有事情.标记线演示等效的投射点

Consider the following code, which essentially does everything you're wishing except invoke a function. The marked line demonstrates the equivalent point-of-cast

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 小时做了一项扎实的工作(实际上我在写这个答案之前就赞成这个答案).然后我认为他错了,同时他认为他的答案不适用.事实证明我们在那次飞跃中错了,因为他第一次是对的,我第二次是错的,现在......呃.

It takes awhile to really stare at this, and admittedly I didn't see it at first either. @sheu did a solid job of catching it about 24 hours before I really thought about it long enough to realize he was right all along (and I actually upvoted that answer before writing this one). Then I thought he was wrong about the same time he thought his answer wasn't applicable. Turns out we were both wrong on that leap, because he was right the first time, I was wrong the second time, and now... ugh.

在 VS2012 和 VS2010 上,标记的行将标记错误而不进行强制转换.clang 会用 C 语言编译它并发出警告,但允许它(我发现这令人惊讶).鉴于,你确实必须真正走出你的快乐地方才能打破它,但它仍然是破碎的.

On VS2012 and VS2010 both the marked line will flag an error without a cast. clang will compile it with a warning in C, but allow it (which I found surprising). Given, you do have to really step out of your happy place to break it, but it is still none-the-less broken.

剩下的就是对识别指针类型、它们的常量以及什么等同于什么的谩骂.

The rest of this is a diatribe on identifying pointer types, their constness, and what is equivalent to what.

关于指针和常量的长篇大论

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

The warning is because char ** and const char ** are not equivalent (duh). To be correct, you could fix the prototype (callee), or fix the caller (by loading an array of const char * and passing that). But can you safely typecast the first to the second? Hmmm....

请记住,按照标准const 会立即转到其左侧 的项目.在数据类型的最左边声明它是该语言支持的一种很好的方式,但通常会引入混淆或问题.根据经验,如果const 出现在decl 的最左边紧邻类型之前,则它适用于数据type不是 后续指针(如果有).当它出现在任何事物的右侧时,它适用于紧接左侧的声明部分,无论是数据类型部分 还是 指针部分,但不管它是什么适用于单个部分.

Remember, by the standard const goes to the item immediately to its left. Declaring it on the most-left of a data type is a nicety that the language supports, but often introduces confusion or problems. As a rule-of-thumb, if const appears on the far-left of a decl immediately before the type, it applies to the data type; not the subsequent pointer (if any). When it appears to the right of anything it applies to the immediate-left decl-part, be it a data type part or a pointer part, but no matter what it only applies to a single 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.

当然谁可以离开家而没有......

And of course who can leave home without...

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++ 中编译时,您只会出现简单的错误,因为参数签名不匹配.但为什么?

So how does this affect your question? When compiling that code in C, without a cast you'll get a compiler warning (or error if compiling with -Werror). When compiling in C++, you'll just plain error because the parameter signature doesn't match. But why?

因为这些没有直接等价:

Because these have no direct equivalence:

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 中给出的确切警告如下:

When compiling with clang, the exact warning in C is given as:

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

main.c:15:9: Passing char ** to parameter of type const char ** discards qualifiers in nested pointer types.

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

VS2010 and VS2012 both, on the other hand, toss an error:

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

error C2440: 'initializing' : cannot convert from 'char **' to 'const char **'

这看起来很奇怪,但实际上 VS 更正确(奇迹永无止境).

It seems odd, but VS is actually more correct (wonders never cease).

这是完全有道理的.位于类型声明中的事实是,第一个不允许修改最终数据,第二个允许.从上面我们知道char **const char **(又名char const **),notem> 一样.一个的底部是一个指向const char的指针,而另一个则有一个指向char的指针.

And that makes perfect sense. Nestled down in the type declaration is the fact that the first of these does not allow modification to the final data, the second does. From above we know that char ** and const char ** (aka. char const **), are not the same. At the bottom of one is a pointer to a const char, while the other has a pointer to char.

这篇关于为什么将 char** 作为 const char** 传递会产生警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆