C 从不兼容的指针类型初始化分配给指针时出现警告
当我使用这段代码时,GCC会给我一个“从不兼容的指针类型初始化”警告(尽管代码运行良好,并且执行了它应该执行的操作,即打印数组的所有元素)C 从不兼容的指针类型初始化分配给指针时出现警告,c,arrays,pointers,C,Arrays,Pointers,当我使用这段代码时,GCC会给我一个“从不兼容的指针类型初始化”警告(尽管代码运行良好,并且执行了它应该执行的操作,即打印数组的所有元素) #包括 内部主(空) { int-arr[5]={3,0,3,4,1}; int*p=&arr; printf(“%p\n%p\n\n”,p); 对于(int a=0;a
#包括
内部主(空)
{
int-arr[5]={3,0,3,4,1};
int*p=&arr;
printf(“%p\n%p\n\n”,p);
对于(int a=0;a<5;a++)
printf(“%d”,*(p++);
printf(“\n”);
}
但是,当我使用这段代码时,不会给出任何警告
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");
}
int main(无效)
{
int-arr[5]={3,0,3,4,1};
int*q=arr;
printf(“%p\n%p\n\n”,q);
对于(int a=0;a<5;a++)
printf(“%d”,*(q++);
printf(“\n”);
}
这两个代码段之间的唯一区别是我分配了*p=&arr和*q=arr
- 到底是什么不同的&制造
- 为什么代码在这两种情况下执行并给出完全相同的输出
arr[0]
的地址实际上相当于指向arr[]
的指针。任何初始化为指向arr[0]
的指针的值都是arr[0]
的地址;这就是指针。阅读指针,尤其是指针与数组的关系。这里有无数的教程,其中一些可能以您的两个案例为例。这些是指向数组(开头)的方法(没有警告),这两种方法都有效:
int *q = arr;
/* OR */
int *q = &arr[0];
这一个介于两者之间,将生成一个警告:
int *q = &arr;
TL;DR检查类型
的类型为&arr
(指向5int(*)[5]
s数组的指针)int
属于arr
类型,但并不总是这样李>int[5]
C11
(重点)
除非它是sizeof
运算符、\u Alignof
运算符或
一元&
运算符,或者是用于初始化数组的字符串文字,一个具有
类型“”的数组“”已转换为类型为“”指向类型“”的指针的表达式
指向数组对象的初始元素,并且不是左值
因此,
int *q = arr; // int[5] decays to int *, == LHS
及
是相同的,然而
int *q = &arr; // LHS (int *) != RHS (int (*) [5])
是不匹配的类型表达式
现在,它可以工作了,因为如中所述,数组变量的地址很可能与数组的第一个元素的地址相同,因此尽管类型不匹配,但值是相同的,因此这似乎可以工作。
给出一个数组指针,一种特殊的指针类型&arr
指向整个数组int(*)[5]
,当用arr
int*q=arr这样的表达式编写时代码>,“衰减”为指向第一个元素的指针。完全等同于
int*q=&arr[0]代码>
int(*)[5]
分配给int*
。这些是不兼容的指针类型,因此会出现编译器诊断消息
事实证明,数组指针和指向第一个元素的int指针在内部很可能具有相同的表示形式和相同的地址。这就是为什么第一个示例“有效”,即使它不是正确的C。当在表达式中用作左值时,数组衰减为指向其第一个元素的指针。所以
int*q=arr
使用数组第一个元素的地址初始化int指针q
:一切正常,不发出警告
但是&arr
是数组的地址。它只能正确用于初始化(或分配)指向数组或相同大小的指针,或指向大小不确定的数组的指针。您可以使用它初始化指向int的指针(int是一种不同且不兼容的类型),编译器会就此发出警告。因为根据标准,使用从指向不同类型的指针初始化的指针是未定义的行为
但在常见的实现中,指向任何类型的指针都具有相同的表示形式,即对象第一个字节的地址。因此,即使标准不允许,指令int*p=arr代码>以与p
相同的值结束,这将给出正确的int*p=arr代码>。这就解释了为什么你的程序仍然给出了期望值
顺便说一句,未定义的行为并不禁止预期的结果,只是不同的编译器可能会给出不同的结果、崩溃、过早结束而没有错误、踢你的狗等等(即使到目前为止还没有编译器可以打我的狗;-)数组类型与(;但不等同于)指向数组项的指针兼容,因此,在第二种情况下没有问题。编译带有gcc-std=c11-pedantic错误的C代码是一种很好的做法,尤其是在学习时。这将阻止您执行无效的C代码。前两个示例都没有指向数组,而是指向数组的第一项(第二个是直接获取其地址,第一个是由于数组衰减)。在许多情况下都会吹毛求疵,但可能与问题的上下文有关。不,&arr
给出的结果类型为int(*)[5]
。这是有道理的。谢谢
int *q = &arr[0]; // RHS == LHS
int *q = &arr; // LHS (int *) != RHS (int (*) [5])