指针示例

指针示例

学习了计算机组成原理之后,对指针有了新的认识

首先是计算机存储结构

当程序运行时,我们关注寄存器和主存

写一段指针的代码

1
2
3
4
5
6
7
int main()
{
int y = 0;
int *p=&y;
*p = 1;
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
	int y = 0;
010216A8 mov dword ptr [y],0
int *p=&y;
010216AF lea eax,[y]
010216B2 mov dword ptr [p],eax
*p = 1;
010216B5 mov eax,dword ptr [p]
010216B8 mov dword ptr [eax],1
return 0;
010216BE xor eax,eax

我的汇编代码格式是Intel的,dword ptr [p]表示一个内存的位置

  • 在指令中,如果指明了某个专用寄存器,也就指明了要处理的数据的尺寸

  • 在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X可以是word或byte ;

  • 有些指令默认了访问的是字单元还是字节单元,比如:push [1000H] 就不用指明访问的是字单元还是字节单元,因为push指令只进行字操作。

Intel的字(word)表示16位数据;一字节八位;b,w,l,q对应1,2,4,8字节

1
2
3
4
5
	int y = 0;
010216A8 mov dword ptr [y],0
int *p=&y;
010216AF lea eax,[y]
010216B2 mov dword ptr [p],eax

所以让指针p指向y实际是三条指令

  1. 把立即数0传到内存y中,给y赋值 int y = 0;

  2. 取内存y的有效地址,传到寄存器eax中 &y;

  3. 把寄存器eax的值,传到内存y中 赋值

c和指针中说,等号左边是地址,右边是一个值,指针存放的是指向的地址
在汇编中,就有了更直观的体现
比如c语言的值传递和地址传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "stdafx.h"
#include <stdio.h>
void swap0(int a0, int b0)
{
int tmp0 = b0;
b0 = a0;
a0 = tmp0;
}
void swap1(int *a1, int *b1)
{
int tmp1 = *b1;
*b1 = *a1;
*a1 = tmp1;
}

int main() {
int x0 = 1,y0 = 2;
int x1 = 2, y1 = 2;
swap0(x0, y0);
swap1(&x1, &y1);
return 0;
}

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	int x0 = 0,x1 = 1;
00C44568 mov dword ptr [x0],0
00C4456F mov dword ptr [x1],1
int y0 = 0, y1 = 1;
00C44576 mov dword ptr [y0],0
00C4457D mov dword ptr [y1],1
swap0(x0, x1);
00C44584 mov eax,dword ptr [x1]
00C44587 push eax
00C44588 mov ecx,dword ptr [x0]
00C4458B push ecx
00C4458C call swap0 (0C41343h)
00C44591 add esp,8
swap1(&y0, &y1);
00C44594 lea eax,[y1]
00C44597 push eax
00C44598 lea ecx,[y0]
00C4459B push ecx
00C4459C call swap1 (0C41348h)
00C445A1 add esp,8
return 0;
00C445A4 xor eax,eax

对比下两边的操作

swap0(值传递) swap1(地址传递)
mov eax,dword ptr [x1] lea eax,[y1]
拷贝了一份值传到寄存器eax 取了y1的地址到eax

swap0

1
2
3
4
5
6
7
8
9
int tmp0 = b0;
00C4169E mov eax,dword ptr [b0]
00C416A1 mov dword ptr [tmp0],eax
b0 = a0;
00C416A4 mov eax,dword ptr [a0]
00C416A7 mov dword ptr [b0],eax
a0 = tmp0;
00C416AA mov eax,dword ptr [tmp0]
00C416AD mov dword ptr [a0],eax

swap1

1
2
3
4
5
6
7
8
9
10
11
12
13
int tmp1 = *b1;
00C416DE mov eax,dword ptr [b1]
00C416E1 mov ecx,dword ptr [eax]
00C416E3 mov dword ptr [tmp1],ecx
*b1 = *a1;
00C416E6 mov eax,dword ptr [b1]
00C416E9 mov ecx,dword ptr [a1]
00C416EC mov edx,dword ptr [ecx]
00C416EE mov dword ptr [eax],edx
*a1 = tmp1;
00C416F0 mov eax,dword ptr [a1]
00C416F3 mov ecx,dword ptr [tmp1]
00C416F6 mov dword ptr [eax],ecx

两边的函数确实都交换了,不同

swap0 swap1
交换拷贝的值 按地址寻址,交换的实际是内存中的值