char a = 0;
char b[20] = {0};
char c[][20] = {{0}};
const char *aPtr;
const char *bPtr;
const char (*cPtr)[20];
char (*dPtr)[20];
void test(void)
{
aPtr = &a;
bPtr = b;
dPtr = &b;
dPtr = c;
cPtr = c; // warning here
}
cPtr = &c; 只有这行代码生成了警告。
../source/bsw/user/PackParam_user.c:21:10: warning: assignment from incompatible pointer type
cPtr = c;
^
我想了解为什么此特定代码行会出现此警告,而其他赋值语句不会触发任何警告。
我使用gcc v4.9
此编译器消息是由于 C 标准中与数组及其元素的
const
相关的缺陷所致。
当将一个指针分配给另一个指针时,无论有或没有限定符,都不指向
void
,C 2018 6.5.16.1 1 中的约束是:
…两个操作数都是指向兼容类型的限定或非限定版本的指针,并且左边指向的类型具有右边指向的类型的所有限定符…
在
cPtr = c;
中,c
的类型为 char [1][20]
,并且它会自动转换为指向其第一个元素的指针,因此结果类型为 char (*)[20]
。它是一个指向 char [20]
类型的指针。
cPtr
的类型为 const char (*)[20]
。它是一个指向const char [20]
的指针。
C 2018 6.7.6.2 6 告诉我们“要使两个数组类型兼容,两者都应具有兼容的元素类型……”但是元素类型
const char
和 char
不兼容,因为 6.7.3 11 说“对于两个限定类型要兼容,两者都应具有兼容类型的相同限定版本……”因此 char [20]
和 const char [20]
不是兼容类型。
现在您可能会说
const char [20]
具有 char [20]
的所有限定符,并且赋值约束允许在指针指向兼容类型时进行赋值,但操作数所指向的类型具有更多限定符。但是, const
修改元素类型 char
,而不是指向的类型,即 20 char
数组。该约束允许将“指向 20 char
数组的指针”分配给“指向 const
20 char
数组的指针”。但这些不是涉及的类型。
他们应该是所涉及的类型。这是C标准的一个缺陷。 20 个
const char
的数组应该与 20 个 const
的 char
数组相同。如果数组元素是 const
,则数组本身实际上也是 const
——任何修改数组的尝试都是修改其元素的尝试,反之亦然。数组是它的元素,因此数组和元素的标识符应该是一回事。但为此编写规则很复杂,并且直到 2018 年 C 标准中还没有完成。
C 标准尝试处理数组上的限定符。您可以尝试使用
cPtr
: const
来使 char
成为指向 20 个 typedef
的 typedef char CharArray[20]; const CharArray *cPtr;
数组的指针。然而,C 2018 6.7.3 10 魔术般地去掉了这个限定符,将其从数组移动到元素:“如果数组类型的规范包含任何类型限定符,则元素类型是如此限定的,而不是数组类型......”回想起来,这是不够的,因为它没有解决数组限定符的问题。
编译器编写者意识到这是标准中的缺陷,并尝试解决它,这就是为什么 GCC 被修改为不发出此警告,除非
-pedantic
特别要求。