否*zippo 不要去位置 15,然后在这个位置找到值。
如果是这样,那么printf(" * ((int **) zippo) = %p\n", * ((int **) zippo) ); 将输出与printf(" *zippo = %p\n", *zippo); 相同的内容,但事实并非如此。
当我运行这段代码时,这是我得到的:
#include <stdio.h>
int zippo[4][2] = {{2, 4}, {6, 8}, {1, 3}, {5, 7}};
int main(){
printf("zippo[0] = %p\n", (void *) (zippo[0]) );
printf(" zippo = %p\n", (void *) zippo);
printf(" *zippo = %p\n", (void *) (*zippo) );
printf(" **zippo = %d\n", (int) ( **zippo) );
printf(" * ((int **) zippo) = %p\n", (void *) (* ((int **) zippo) ));
}
这是我得到的:
zippo = 0x804a040
*zippo = 0x804a040
**zippo = 2
* ((int **) zippo) = 0x2
我使用gcc -Wall -Wextra -Wpedantic -pedantic 编译了这段代码,以确保没有隐藏任何警告,并且选项-m32 具有32 位地址(与int 大小相同)。
我实际上很难理解那里发生了什么,所以我决定看看相应的汇编代码。使用gcc -S file.c -o file.s 我得到以下内容。
第一个变量声明:
.globl zippo
.data
.align 32
.type zippo, @object
.size zippo, 32
zippo:
.long 2
.long 4
.long 6
.long 8
.long 1
.long 3
.long 5
.long 7
.section .rodata
.LC0:
.string "zippo[0] = %p\n"
.LC1:
.string " zippo = %p\n"
.LC2:
.string " *zippo = %p\n"
.LC3:
.string " **zippo = %d\n"
.LC4:
.string " * ((int **) zippo) = %p\n"
printf("zippo[0] = %p\n", (void *) (zippo[0]) ); 的对应程序集:
movl $zippo, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
printf(" zippo = %p\n", (void *) zippo); 的对应程序集:
movl $zippo, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
printf(" *zippo = %p\n", (void *) (*zippo) ); 的对应程序集
movl $zippo, %esi
movl $.LC2, %edi
movl $0, %eax
call printf
printf(" **zippo = %d\n", (int) ( **zippo) ); 的对应程序集:
movl $zippo, %eax
movl (%rax), %eax
movl %eax, %esi
movl $.LC3, %edi
movl $0, %eax
call printf
printf(" * ((int **) zippo) = %p\n", (void *) (* ((int **) zippo) )); 的对应程序集
movl $zippo, %eax
movq (%rax), %rax
movq %rax, %rsi
movl $.LC4, %edi
movl $0, %eax
call printf
正如您在此处所注意到的,对于前 3 个 printf,对应的程序集完全相同(变化的是 LCx,它对应于格式)。
最后 2 个 printf 也是一样。
我的理解是,由于编译器知道zippo 是一个二维数组,因此知道*zippo 是一维数组,其数据从第一个元素的地址开始。