编辑:问题深入here解释更多(谢谢@Eric Postpischil)。这似乎是在海湾合作委员会的错误。
首先,让我先从一些背景:我在写使用的API,我不能更改代码,在GCC的版本我无法改变,与编译标志我不能删除,而当我米,完成它必须有精确的零警告或编译指示。
编辑:没有工会无论是。
EDIT2:假设构建系统还采用了-Wall -ansi -pedantic在阳光下每隔警告。我要确认版本的GCC明天,但我敢肯定它不是上述GCC 7.我与GCC 6.3测试其间。
EDIT3:我标记问题作为“回答”。为了完整起见,我添加下面的一些详细信息:
我检查所使用的编译版本,它不漂亮。我们使用的MinGW和gcc.exe --version
告诉我这是GCC 3.4.5。
此外,编译标志包括wall wextra wcast-qual wpointer-arith wconversion wsign-conversion
与其他不相关手头的问题一起。
考虑下面的代码:
#include "stdio.h"
#include "stdint.h"
typedef uint32_t MyType[4];
const MyType* foo(const uint8_t* a)
{
return (const MyType*) a;
}
void myapi_foo(const MyType* d) {}
int main()
{
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
myapi_foo(b);
return 0;
}
与海湾合作委员会和-Wcast-QUAL标志编译,该代码会抛出以下警告:
警告:投丢弃“常量”指针目标类型[-Wcast-QUAL]返回(常量的MyType *)限定符;
编辑:澄清,错误的是在这条线:
return (const MyType*) a;
我知道问题的根本原因是typedef的类型MyType
这实际上是一个数组。可悲的是,我没有修改此类型定义的奢侈品,也不是API函数myapi_foo
和参数类型的可疑的选择。说实话,我真的不明白,为什么是编译器,不满意这个转换,所以澄清非常欢迎。
什么是指示编译器都应该被视为一个指向常量数据的干净的方式?
以下是我已经找到,但给我留下不满意的几个“解决方案”:
return (const MyType*) (uint32_t) a;
。这是非常简陋,但使用uint32_t
内存地址在这个项目的先例,所以我可能不得不使用它作为最后的努力。return (const void*) a;
,无论哪个会工作sizeof(MyType*)
价值的建议。遗憾的是它并没有对目标工作。感谢您的时间。
这是GCC bug 81631。 GCC没有认识到剧组来const MyType *
保留const
预选赛。这可能是因为,在这个“指针到四个const uint32_t
的数组”,GCC执行的阵列是const
是否比是否阵列元件是const
测试。
在某些GCC版本,包括8.2,一个解决方法就是改变:
return (const MyType*) a;
至:
return (const void *) a;
很可能在更多的版本到工作中更加剧烈的变化是使用:
return (const MyType *) (uintptr_t) a;
这可能是因为此代码将a
到蒙上它const MyType *
一个功能相关的问题:
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
在许多C实现,MyType
,作为uint32_t
的阵列,将需要四个字节对齐,但将a
只需要一个字节对齐。的每个C 2018 6.3.2.3 6,如果a
未正确对MyType
对齐时,转换的结果没有定义。
此外,该代码表明uint_t
阵列a
可以用作4个uint32_t
的阵列。这将违反Ç别名规则。你在问题中显示的代码似乎是一个样品,而不是实际的代码,所以我们不能肯定,但你应该考虑这一点。
你可以这样做:
const MyType* foo(const uint8_t* a)
{
union {
const uint8_t* a;
const MyType* b;
} v;
v.a = a;
return v.b;
}
w.c是你修改的文件:
pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wcast-qual w.c
pi@raspberrypi:/tmp $
该工程无论编译器(没有的#pragma)或int和指针(int和指针之间没有投)各自的大小,但我不知道这是非常优雅;-)
奇怪的是有一个foo的功能,并在同一时间Wcast-qual
编译,这是矛盾的
编辑,如果你不能使用union你也可以做到这一点
const MyType* foo(const uint8_t* a)
{
const MyType* r;
memcpy(&r, &a, sizeof(a));
return r;
}
编译:
pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wcast-qual w.c
pi@raspberrypi:/tmp $
如果实在不行,你可能会喜欢用uintptr_t
hammer,实施提供了它。它是由C11标准可选:
const MyType* foo(const uint8_t* a)
{
uintptr_t uip = (uintptr_t) a;
return (const MyType*) uip;
}