GCC发出不兼容指针类型的警告

7
当我使用GCC 4.9.2编译以下程序时,出现以下警告:传递给‘P’的第1个参数类型不兼容。然而,我没有发现程序有任何错误。有什么线索吗?
typedef int Row[10];

void P(const Row A[])
{
}


int main(void)
{
    Row A[10];

    P(A);
    return 0;
}

这是来自GCC的完整错误输出:

test.c: In function ‘main’:
test.c:12:4: warning: passing argument 1 ofP’ from incompatible pointer type
  P(A);
    ^
test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type ‘int (*)[10]’
 void P(const Row A[])
      ^

编辑:该程序能够在Clang 3.5.0和选项-pedantic -std=c89 -Wall的情况下编译成功。


2
你认为“const”限定符怎么样? - Sourav Ghosh
1
@SouravGhosh 这个函数需要一个 int (*)[10] 类型的参数,可以是常量也可以不是。你有不同的看法吗? - August Karlstrom
你想要类似 http://ideone.com/g0RxuW 这样的东西吗? - mch
@nos 好的,那么这就是编译器的一个错误。如果您使用了“-std=c99”,则应该会收到一条诊断信息。您发布的链接也明确说明了这一点。 - Lundin
(显然,-std=gnu11的人想通过这个非标准扩展来展示语言的改进方式。因此,这是一个很好的扩展,但可悲的是它还不符合标准。) - Lundin
显示剩余8条评论
1个回答

8
摆脱typedef,这样就会变得更清晰一些:
void P (const int A [][10])
{
}

int main(void)
{
    int A[10][10];

    P(A);
    return 0;
}

问题在于函数参数中的数组会“衰减”为类型为const int(*) [10]的指向数组的指针,其中的项是const。这种指针类型与从main传递的不兼容,因为该数组衰减为类型为int(*)[10]的数组指针。
有一个“指向类型的指针可以转换为限定符指向类型的指针”的规则。例如,int*可以转换为const int*,但反过来不行。但这个规则在这里不适用。
因为“指向数组的指针”的限定版本是“指向常量数组的指针”,而不是你这里拥有的“指向常量数组的指针”。
不幸的是,这是C语言的一个弱点:在使用数组指针时无法实现常量正确性。唯一的解决方案是非常丑陋的:
P( (const int(*)[10]) A);

针对这种情况,为了增加可读性,完全可以跳过const正确性。


编辑:在C11中,您可以像这样操作,它更加类型安全,但仍然依赖于调用者执行转换:

#define const_array_cast(arr, n) _Generic(arr, int(*)[n] : (const int(*)[n])arr )

void P (const int A [][10])
{
}


int main(void)
{
    int A[10][10];

    P(const_array_cast(A,10));
    return 0;
}

不需要将 const 传递给具有 const 参数的函数。函数中的 const 只是表示参数在函数中不会被修改。例如,可以参考 strcmp 函数。 - Rishikesh Raje
程序使用选项-pedantic -std=c89 -Wall可以在Clang 3.5.0上干净地编译。这是否意味着Clang存在漏洞? - August Karlstrom
2
@RishikeshRaje 请再次阅读我的回答,我已经明确解释了你所说的内容,在这里不适用。 - Lundin
相关问题 - Lundin
@AugustKarlstrom 这听起来确实像是编译器的一个 bug。 - Lundin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接