让我们先看看内存布局:
char arr[5][7][6];
这arr
是一个数组数组。
它将被布置到内存中,如下所示:
+--------------+
| | arr[0]
+--------------+
| | arr[1]
+--------------+
| | arr[2]
+--------------+
| | arr[3]
+--------------+
etc.
现在arr[i]
是一个数组的数组char
。
所以a[i]
会像
+--------------+ a[i][0]
| |
+--------------+
| | a[i][1]
+--------------+
| | a[i][2]
+--------------+
| | a[i][3]
+--------------+
etc
现在arr[i][j]
是一个数组chars
。
所以
+--------------+
| | arr[i][j][0]
+--------------+
| | arr[i][j][1]
+--------------+
| | arr[i][j][2]
+--------------+
etc.
编译器将在其符号表中使用名称arr
和第一个块的地址创建一个条目,并跟踪总大小(5*6*7 = 210 字节)。
现在的表达
printf("%d\n", (&arr + 1) - &arr);
它是一个指针算法。所以它将绑定到每个符号的类型。
让我们看看这个在行动。
(gdb) p &arr
$1 = (char (*)[5][7][6]) 0x7fffffffe160
你看的类型arr
是指针char (*)[5][6][7]
换句话说,它指向数组数组的数组。指针算术实际上与指针指向的类型有关。所以重要的是类型的大小。
(gdb) p sizeof(char [5][7][6])
$2 = 210
因此,任何指向该类型的指针char [5][6][7]
都将递增或递减,如下所示:
&arr+1 => 0x7fffffffe160 +0xd2 => 0x7fffffffe232
和(&arr + 1) - &arr => 0x7fffffffe232 - 0x7fffffffe160=> 0xd2
现在它实际上返回0xd2。但对于指针算术,这意味着1*sizeof(char [5][7][6]) => 1
指针算术返回number of sizeof(type)
而不是实际的字节偏移量。
你得到正确的结果
printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
由于强制转换,您将其设为 char 指针。所以指针运算将使用sizeof(char)
1 字节大小的单位。因此输出将是 210。
printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
这里arr
的表达式将衰减为类型char (*)[7][6]
所以它是一个指向二维数组的指针。它指向的类型的大小为 6*7 = 42。这就是你得到的结果。
printf("%d\n", (unsigned)(p + 1) - (unsigned)p);
在这里,p+1 - p
将导致指针算术1 * sizeof(char(*)[5][6][7])
。所以在指针算术中,它应该返回 1。但是由于您将结果转换为 unsigned ,它将放弃指针算术并使用整数算术。因为使用整数运算,它会处理大数的指针值,所以你会得到实际的字节偏移量。