【发布时间】:2019-06-27 09:09:31
【问题描述】:
编辑:更深入地解释了问题here(谢谢@Eric Postpischil)。这似乎是 GCC 中的一个错误。
首先,让我从一些上下文开始:我正在编写的代码使用了一个我无法更改的 API,在一个我无法更改的 GCC 版本上,我不允许删除编译标志,以及当我完成它时,它必须精确为零警告或#pragmas。
编辑:也没有工会。
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;
}
使用 GCC 和 -Wcast-qual 标志编译,此代码将引发以下警告:
警告:cast 丢弃来自指针目标类型的“const”限定符 [-Wcast-qual] return (const MyType*) a;
编辑:澄清一下,错误在这一行:
return (const MyType*) a;
问题原因
我知道问题的根本原因是 typedef 类型 MyType 实际上是一个数组。遗憾的是,我没有修改这个 typedef 的奢侈,也没有修改 API 函数myapi_foo 及其参数类型的可疑选择。
老实说,我真的不明白为什么编译器对这个演员阵容如此不满,所以澄清一下是非常受欢迎的。
问题
向编译器指示所有内容都应该被视为指向 const 数据的指针的最干净方式是什么?
废弃的和潜在的解决方案
以下是一些我发现但令我不满意的“解决方案”:
- 删除 -Wcast-qual 标志。由于代码质量规则,我不能这样做。
- 添加#pragma 以关闭该部分代码周围的警告(如here 所示)。同样,我也不能这样做。
- 将指针转换为整数,然后再转换回指针(如图所示here)
return (const MyType*) (uint32_t) a;。这是非常粗略的,但是在这个项目中使用uint32_t作为内存地址是有先例的,所以我可能不得不将它作为最后的努力。 - 编辑:@bruno 建议使用联合来回避问题。这是一个便携且相当优雅的解决方案。但是,上述代码质量规则完全禁止使用联合。
- 编辑:@Eric Postpischil 和@M.M 建议使用 (const void*) cast
return (const void*) a;,无论sizeof(MyType*)的值如何,它都可以工作。遗憾的是,它对目标不起作用。
感谢您的宝贵时间。
【问题讨论】:
-
您应该指定您正在使用的 GCC 版本以及报告错误的行。
-
如警告消息中所述,错误出现在 return (const MyType) a;* 我手头没有特定的 GCC 版本,但我可以重现GCC 6.3.0 的问题。明天我会用我可以分享的信息更新 OP。
-
return (const void *) a;是否符合您的编码标准? -
我添加了另一个在 GCC 6.3 中有效的解决方法。
标签: c arrays gcc constants typedef