我正在探索typedef,偶然发现了这个程序
编辑:几乎所有答案都与它生成的警告有关。因此,我继续删除所有警告,但问题仍然相同。
#include<stdio.h>
typedef int int3[3];
int main(){
int a[2][3] = {{1,2,3}, {4,5}};
int3 *p = a;
int *ip = (int *) a;
printf("sizeof:\np: %lu\n(*p+0): %lu\n**p: %lu\nip: %lu\n*ip: %lu\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
printf("---\n");
printf("p: %p\tp+1: %p\n*p: %p\t*p+1: %p\n**p: %d\nip: %p\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
return 0;
}
在一次运行中显示:
sizeof:
p: 8
(*p+0): 8
**p: 4
ip: 8
*ip: 4
---
p: 0x7ffe36df31b0 p+1: 0x7ffe36df31bc
*p: 0x7ffe36df31b0 *p+1: 0x7ffe36df31b4
**p: 1
ip: 0x7ffe36df31b0
*ip: 1
我的问题是:
如果p和* p相等
和** p = 1
那为什么不也* p = 1?
提供的指针大小= 8,整数大小= 4
即使考虑到指针算术,* p也应至少为0xkk kk kk kk 00 00 00 01
k为任何十六进制数字(考虑little-endian)
因为取消引用与int相同的地址应该给1
编辑: 为了使事情更清楚,请考虑以下表格:
+-----------+----------------------+------------------+
|Variable | Value | Address |
| | | |
| | | |
| p | 0x7ffe36df31b0 | |
| | | |
|*p | 0x7ffe36df31b0 | 0x7ffe36df31b0 |
| | | |
|**p | 1 | 0x7ffe36df31b0 |
+-----------+----------------------+------------------+
* p和** p如何具有相同的地址但值不同?
答案 0 :(得分:2)
首先,请注意,此代码在混乱的约束冲突杂乱混搭中与array decay结合使用,产生了有用的可疑输出。但是,我将尝试回答您有关正在发生的事情的问题,并尝试使用平凡的解释而不求助于C标准的引用,因为其他人已经以这种方式回答了问题。
* p和** p如何具有相同的地址但值不同?
因为p
是指向数组的指针。
给出
typedef int int3[3];
int3 *p;
这意味着*p
是三维数组。请注意
int3 *p = a;
如其他地方所述,是违反约束的。您可以 force 强制执行“强制转换”操作,但是从根本上来说还是错误的,并且代码只能“放弃”,因为数组的地址就是该数组的第一个元素的地址-和您当前的实现并没有以足够大的方式区分指针类型,因为它们根本上是不兼容的。选择一个实现,其中普通int *
是32位偏移值,而数组将同时具有32位段和 32位偏移值作为其地址,如果代码没有完全失败,它很可能会产生废话。这就是C标准要求指针必须为“兼容类型”的原因-因为指针根本不需要兼容。
除了这个问题,您的实现上的初始化/赋值似乎可以被视为
int3 *p = ( int3 * ) a;
由于“有效”,这意味着p
包含int
值的三元素数组的地址。因此,用p
解引用*p
与a[0]
或二维int
数组中的前三个元素a
数组相同。
那么*p
是什么?
在这种情况下,它与数组a[0]
完全相同。这样的裸数组引用decays to an address *,并且该地址与指向数组元素的指针具有相同的 type 类型。并且该地址的值将是数组第一个元素的地址。
因此*p
是int
的三元素数组,它本身可以被取消引用并求值到a[0]
或a[0][0]
的第一个元素。因此,**p
与a[0][0]
相同。
a[0][0]
-或**p
-是一个int
,它的初始化值为1
。
*p
是a[0]
和第一个元素的地址。
*-很多人说数组“衰减指针”或“数组是指针”,但我喜欢“衰减地址”,因为可以将指针分配给一个地址,而仅将地址分配给是-它不能分配给自己,就像不能将数组本身分配给它一样,但是可以将地址分配给其他内容,例如指针。请注意,当数组传递给函数时,数组的地址实际上是作为实际指针传递的。指针是函数的参数,可以将该函数参数分配给...
答案 1 :(得分:1)
发布的代码,当使用以下命令编译时:
gcc -c -Wall -Wextra -Wconversion -pedantic -std=gnu11
导致以下编译器消息:
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip = a;
^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~~
%ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
Compilation finished successfully.
编译器通过说编译成功而结束。这并不意味着可以运行此代码并期望获得有效的结果/输出。
更正代码以使其干净编译后,请对包含修改/更正代码的问题发表EDIT。
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled.c" (in directory: /home/richard/Documents/forum)
untitled.c: In function ‘main’:
untitled.c:6:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip = a;
^
untitled.c:7:26: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:38: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:47: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:55: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:7:64: warning: format ‘%d’ expects argument of type ‘int’, but argument 6 has type ‘long unsigned int’ [-Wformat=]
printf("sizeof:\np: %d\n(*p+0): %d\n**p: %d\nip: %d\n*ip: %d\n",sizeof p, sizeof (*p+0), sizeof **p, sizeof ip, sizeof *ip);
~^
%ld
untitled.c:9:17: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
untitled.c:9:26: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (*)[3]’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~
untitled.c:9:34: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
untitled.c:9:44: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^ ~~~~
%ls
untitled.c:9:61: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘int *’ [-Wformat=]
printf("p: %x\tp+1: %x\n*p: %x\t*p+1: %x\n**p: %d\nip: %x\n*ip: %d",p,p+1,*p,*p+1,**p,ip,*ip);
~^
%ls
Compilation finished successfully.
答案 2 :(得分:0)
这里有约束冲突,因为您在以下初始化中使用了不兼容的指针类型:
int *ip = a;
根据Pointer declarators上的C11标准部分
要使两个指针类型兼容,则两者必须具有相同的限定条件,并且都应是指向兼容类型的指针。
和Simple assignment/Constraints
左操作数具有原子,合格或不合格的指针类型,并且(考虑到左操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的合格或不合格版本的指针,并且由左侧具有右侧所指向类型的所有限定词;
在这种情况下,编译器需要发出诊断信息:
<source>:8:15: warning: initialization of 'int *' from incompatible pointer type 'int (*)[3]' [-Wincompatible-pointer-types] int *ip = a;
请参见Demo
编译程序时,好的做法是启用所有警告并将警告视为错误,以便(尽可能)避免这种行为。