在C中正确地将const void指针强制转换为const char指针数组

我有一段看起来像这样的C代码:

const char (*foo)[2] = bar(); 

现在bar()是一个返回(const void *) 。 如何正确转换此const指针? 该代码从GCC产生此警告:

 "initialization discards qualifiers from pointer target type". 

以下是我不成功的一些尝试:

 const char (*foo)[2] = (const char *)bar(); const char (*foo)[2] = (const void **)bar(); 

原始代码确实有效,我只是无法通过正确转换返回值来消除警告。

编辑:有人建议:

 const char (*foo)[2] = (const char (*)[2])bar(); 

它似乎是正确的,但GCC给出了这个警告:

 "cast discards qualifiers from pointer target type" 

这几乎与原始警告相同。

编辑2:好的,我想我已经知道了。 这里真正的问题是bar()( const void * )定义。 定义中的const (const char( * )[2])引用数组的元素,而不是指向数组的指针。 这种类型定义本质上是一个数组,当由void指针表示时,它不是 const 。 真正的答案是( const void * )在转换为(const char ( * )[2])时失去了它的cons

其他几个人已经说出了正确的演员表,但它会产生虚假的警告 。 该警告来自C标准中可能存在的错误 ,或者(取决于您的解释)GCC应特别处理的情况。 我相信const限定符可以安全无误地提升到数组类型。 您可以使用-Wno-cast-qual删除该警告,但当然这将消除您实际关注的案例的警告。

详细说明,类型const char (*)[2]表示“指向const char数组(长度为2)”。 该数组未标记为const ,只是数组的元素。 与const void *类型相比,编译器注意到后者是指向const的指针,而前者不是,因此生成警告。 C标准没有办法将数组标记为const ,即使const数组等同于const数组。

尝试:

 const char (*foo)[2] = (const char (*)[2])bar(); 

编辑但如果bar返回指向const指针的const数组的指针作为您的问题标题提示,则如果您指定此类型的变量,则不需要进行强制转换:

 char* const* foo = bar(); 

最新版演员的警告问题具有历史根源。 您知道C语言(以及C ++)正确禁止T** -> const T**转换。 这是正确的,因为允许这种转换会为某些细微违反const-correctness规则的行为开辟道路(可以在任何自尊的常见问题解答中找到)。

但是,C语言也禁止T** -> const T* const*转换。 这与允许这种转换的C ++不同。 (此转换不违反常量。)这一直被认为是C语言规范中的“设计缺陷”。 这个缺陷已经在C ++中“修复”了,但它仍然存在于C中(即使在C99中)。 坦率地说,我不知道为什么它在C99中保持不变。 该缺陷的“后果”之一(或者更准确地说,是处理常量正确性的方法)是在C语言中T (*)[N] -> const T (*)[N]转换也是被禁止的即使它对const正确性没有任何内在威胁。

我无法重现您使用我的GCC版本发出的警告。 但如果你得到它,它似乎只是同一意识形态的另一个结果。 如果考虑到转换是由显式强制转换运算符请求的,则GCC警告完全没有道理。 您可以尝试使用链式强制转换来解决警告问题

 const char (*foo)[2] = (const char (*)[2]) (void *) bar(); 

只需注意,您不需要数组维度:

 const void *bar() { static const char a[10] = "abcdefghij"; return &a[4]; } int main() { const char (*foo)[2] = (const char (*)[])bar(); return 0; } 

由于这可能有些人难以阅读:

 cdecl> explain const char (*foo)[2] declare foo as pointer to array 2 of const char 
 const char (*foo)[2] = (const char (*)[2])bar();