【发布时间】:2019-02-03 21:38:54
【问题描述】:
考虑下面的代码,它来自this question:
const int (*foo(const char *a))[1]
{ return (const int (*)[1]) a; }
compiled with GCC 8.2 (and older versions) using -Wcast-qual 时,GCC 会发出警告:
这个警告正确吗?显然,目标类型中有一个 const 限定符。
它在元素类型上,而不是在指针直接指向的东西上,即数组类型。然而,即使我们使用typedef int T[1]; 并用(const T *) 替换演员表,警告仍然存在。此外,根据 C 2018 6.7.3 10,数组类型的限定符适用于元素类型,而不是数组类型,因此类型是相同的。
Clang 不显示此警告。
如果我们将演员更改为(const void *):
const int (*foo(const char *a))[1]
{ return (const void *) a; }
然后警告消失。如果我们将-pedantic 添加到编译开关,我们会收到关于const 的不同警告:
这看起来像相同的警告,除了它是关于从返回表达式到函数返回类型的隐式转换,而前面的警告是关于强制转换中的显式转换。但是这个只出现在-pedantic。为什么?
【问题讨论】:
-
对我来说看起来像一个 gcc 错误?这是一个返回类型的 typedef 版本仍然显示问题:godbolt.org/z/mC8qS6
-
纯猜测:可能是您在问题中确定了“数组类型上的限定符适用于元素类型”的问题。 GCC 可能会看到“指向(const char)的指针”到“指向((const int)的数组)的指针”,看到指向的东西不是const,发出警告(实际上它如果它愿意更深一层,它仍然是 const)。
-
注意:从指向
char的指针更改为int会引发对齐问题。 -
如果你想检验我的假设,这个警告会在 gcc/c/c-typeck.c 的
handle_warn_cast_qual中生成,在discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) & ~TYPE_QUALS_NO_ADDR_SPACE (in_type));的两行中。您必须深入了解in_otype以查看它是否为数组类型,以及元素类型是否设置了base.readonly_flag位。 -
用
(int (*)[1])(const int(*)[1])42;甚至typedef int T[1]; (T*)(const T*)42;铸造const对gcc 和clang 都没有警告。
标签: c gcc language-lawyer