38

我一直收到这个警告:

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

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

4

4 回答 4

58

简答

你可以安全地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

于 2013-01-28T16:11:10.240 回答
39

编辑:我什至回答了错误的问题。我的回答完全无关紧要!请忽略我。

编辑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你死了。所以不行 :-)

于 2013-01-28T13:21:50.313 回答
1

警告告诉您,您正在调用的函数需要给定的参数,const char**但您正在传递一个char**参数。要摆脱这个警告,你可以

  • 真的传入一个const char**
  • 将您的参数转换为 a const char**(就像您目前正在做的那样)
  • 更改函数原型,使函数期望char**
于 2013-01-28T13:16:38.013 回答
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。

我不认为编译器应该阻止你做更多的事情。

于 2020-06-30T17:28:02.370 回答