在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();