分配给指针时从不兼容的指针类型警告初始化

Nat*_*thu 9 c arrays pointers

当我使用这段代码时,GCC给我一个'来自不兼容指针类型的初始化'警告(虽然代码工作正常并且做了它应该做的事情,它打印了数组的所有元素).

#include <stdio.h>

int main(void)
{
    int arr[5] = {3, 0, 3, 4, 1};
    int *p = &arr;

    printf("%p\n%p\n\n", p);

    for (int a = 0; a < 5; a++)
        printf("%d ", *(p++));
    printf("\n");
}
Run Code Online (Sandbox Code Playgroud)

但是当我使用这段代码时没有给出警告

int main(void)
{
    int arr[5] = {3, 0, 3, 4, 1};
    int *q = arr;

    printf("%p\n%p\n\n", q);

    for (int a = 0; a < 5; a++)
        printf("%d ", *(q++));
    printf("\n");
}
Run Code Online (Sandbox Code Playgroud)

这两个片段之间的唯一区别是我指定*p =&arr和*q = arr.

  • 究竟有什么不同和制作?
  • 为什么代码在两种情况下都会执行并提供完全相同的输出?

Lun*_*din 15

  • &arr给出一个数组指针,一个特殊的指针类型int(*)[5],它指向整个数组.
  • arr当用表达式写入时int *q = arr;,"衰减"成指向第一个元素的指针.完全等同于int *q = &arr[0];

在第一种情况下,您尝试将a分配int(*)[5]给a int*.这些是不兼容的指针类型,因此是编译器诊断消息.

事实证明,数组指针和指向第一个元素的int指针很可能在内部具有相同的表示和相同的地址.这就是为什么第一个例子"工作"即使它不正确C.


Sou*_*osh 5

TL;DR检查类型。

\n\n
    \n
  • &arr是类型int (*) [5](指向 5数组的指针int)。
  • \n
  • arr是类型int [5],但并非总是如此
  • \n
\n\n

引用C11,章节 \xc2\xa76.3.2.1,(重点是我的

\n\n
\n

除非它是运算sizeof符、_Alignof运算符或一元运算&符的操作数,或者是用于初始化数组的字符串文字, \n 类型为\xe2\x80\x98\xe2\x80\x98array 的表达式类型为 \xe2\x80\x99\xe2\x80\x99 的表达式转换为类型为\xe2\x80\x98\xe2\x80\x98 的表达式,指向类型为\xe2\x80\x99\xe2\x80\x99 的指针,该指针指向\ n 为数组对象的初始元素,并且不是左值。

\n
\n\n

因此,

\n\n
 int *q = arr;   // int[5] decays to int *, == LHS\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
 int *q = &arr[0];   // RHS == LHS\n
Run Code Online (Sandbox Code Playgroud)\n\n

是相同的,然而,

\n\n
 int *q = &arr; // LHS (int *) != RHS (int (*) [5])\n
Run Code Online (Sandbox Code Playgroud)\n\n

是一个不匹配的类型表达式。

\n\n

现在,它可以工作,因为,正如Lundin\'s 答案中已经提到的,数组变量的地址可能与数组第一个元素的地址相同,因此尽管类型不匹配,但值相同的,所以这似乎有效。

\n