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

nhhxz33t  于 2023-08-03  发布在  其他
关注(0)|答案(4)|浏览(149)

我一直收到这样的警告

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

字符串
现在,我通过将参数强制转换为const char **来传递参数。有没有别的方法可以摆脱它?

iyfamqjs

iyfamqjs1#

简短回答

你能安全地把char **转换成const char**吗?* 不 。(反正不安全),原因远比你想象的要微妙得多。你能用别的方法处理掉它吗?当然可以。从char*值中加载const 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小时之前,我真的思考了足够长的时间,意识到他沿着是正确的(实际上,我在写这一个之前投票支持这个答案)。然后我认为他错了,就在他认为他的答案不适用的时候。结果我们两个都错了因为他第一次是对的我第二次错了现在...啊。
在VS 2012和VS2010上,标记的行都将标记错误,而不进行强制转换。clang将在C语言中编译它并带有警告,但允许它(我发现这很奇怪)。当然,你必须真正走出你的快乐之地,才能打破它,但它仍然是坏的。
其余的部分是对标识指针类型、它们的常量以及什么等价于什么的谩骂。
"关于指针和常数的长篇大论"
此警告是因为char **const char **不相等(duh)。正确的做法是,您可以修复原型(被调用方),或者修复调用方(通过加载const char *数组并传递该数组)。但是你能安全地把第一个转换成第二个吗?嗯......
请记住,根据标准const会直接转到其 * 左侧 * 的项目。在数据类型的最左边声明它是该语言支持的一个很好的方法,但经常会带来混乱或问题。作为一个经验法则,如果const出现在decl的最左边,就在类型之前,它适用于data type;后续指针(如果有)。当它出现在任何东西的右侧时,它应用于紧邻左侧的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语言中的确切警告如下所示:
主.c:15:9:将char **传递给const char **类型的参数会丢弃嵌套指针类型中的限定符。
另一方面,VS2010和VS 2012都会抛出一个错误:
错误C2440:“正在初始化”:无法从'char**'转换成'const char**'
这看起来很奇怪,但VS实际上更正确(奇迹从未停止)。
这完全说得通。嵌套在类型声明中的事实是,第一个不允许修改最终数据,而第二个 * 允许修改 *。从上面我们知道char **const char **(即,char const **),是 * 不 * 相同的。一个的底部是指向const char的指针,而另一个的底部是指向char的指针。

6vl6ewon

6vl6ewon2#

这是一个有趣的C语言,如果你认真思考,这是有意义的。
基本上,转换:

char** ptr;
const char** const_ptr;
const_ptr = ptr;  // <-- BAD!

字符串
不允许。
你可能会问,为什么?“我在让事情变得更稳定!这显然是一件好事!“
想想看如果允许这样做,那么:

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.


你死定了。所以...不:-)

3bygqnnd

3bygqnnd3#

警告告诉您,您正在调用的函数期望给定的参数为const char**,但您正在传递char**参数。要消除此警告,您可以

  • 真的传入一个const char**
  • 将参数强制转换为const char**(就像你现在做的那样)
  • 更改函数原型,使函数期望char**
zf9nrax1

zf9nrax14#

我还是觉得这样不对。在示例中:

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 char *const *const_ptr


然后

*const_ptr = &c


是正确的,它不会让你赋值给const char c。
我不认为编译器应该阻止你做一些更常量的东西。

相关问题