结论在前:数组名是纯地址值,不是指针。
反汇编的方法分析:
void fun(int *a,int *b){}
int main()
{
int a[]={1};
int bb=1;
int *b=&bb;
fun(a,b);
fun(a,&bb);
}
使用g++ -g temp.cpp
编译出二进制,并使用objdump -S a.out
进行反汇编,以下为截取的部分汇编代码:
int a[]={1};
1177: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%rbp)
int bb=1;
117e: c7 45 e4 01 00 00 00 movl $0x1,-0x1c(%rbp)
int *b=&bb;
1185: 48 8d 45 e4 lea -0x1c(%rbp),%rax
1189: 48 89 45 e8 mov %rax,-0x18(%rbp)
fun(a,b);
118d: 48 8b 55 e8 mov -0x18(%rbp),%rdx
1191: 48 8d 45 f4 lea -0xc(%rbp),%rax
1195: 48 89 d6 mov %rdx,%rsi
1198: 48 89 c7 mov %rax,%rdi
119b: e8 a9 ff ff ff callq 1149 <_Z3funPiS_>
fun(a,&bb);
11a0: 48 8d 55 e4 lea -0x1c(%rbp),%rdx
11a4: 48 8d 45 f4 lea -0xc(%rbp),%rax
11a8: 48 89 d6 mov %rdx,%rsi
11ab: 48 89 c7 mov %rax,%rdi
11ae: e8 96 ff ff ff callq 1149 <_Z3funPiS_>
可以看到
- 数组起始地址为
0xc
- int变量的地址为
0x1c
- 指向int变量的指针的地址为
0x18
lea
代表将纯地址送给寄存器
mov
代表将地址上的内容送给寄存器
观察fun(a,b);
和fun(a,&bb);
,其中前者是一个mov指令和一个lea指令,后者是两个lea指令。而&bb
是右值纯地址值,这说明数组名和&bb一样是纯地址值。
不从汇编角度分析,从逻辑角度分析:
数组名不占用堆栈空间,指针占用堆栈空间(全局指针占用data段空间)。
大多数场景下,由于两者的数值相等,很多人容易混着用,但是容易出bug。参见《C专家编程》里对数组名和指针的讨论,主要是使用export时,混用数组名和指针会出现bug。
函数名也是和数组名一样,属于纯地址值,并非是指针,不占用堆栈空间。