目录
1. 用C++语言测试
2. 用汇编语言测试(MASM环境)
指向数组的指针存储的是连续的内存地址,而内存地址的最小编址单位是1字节,如果存储的数据本身移动几个字节,则内存地址也相应地移动几个字节。而数组指针的加1移动几个字节,取决于所指向的数组类型,这部分是由C/C++的编译器实现去处理的。下面具几个例子说明(下面的例子在MSVC的X64平台,指针本身占8个字节):
(1) 指向1字节的数组指针:
void TestPointerSize()
{
char data[] = {1,2,3,4,5,6,7,8,9,10};
char* ptr = data;
printf("ptr size=%d,data=%I64d\n",sizeof(ptr),data);
for(int i=0;i<10;i++)
{
printf("data[%d]=%d,ptr=%I64d\n",i,*ptr,ptr);
ptr = ptr + 1;
}
}
输出如图:
从图中可以看到,指针本身的大小占8个字节,数组名是数组的首地址,常量指针。但注意,sizeof(data)是计算整个数组的存储大小,而不是首地址的大小。指针每次加1,也是加1字节长度,即1个数组元素的大小。
(2) 指向2字节的数组指针:
void TestPointerSize()
{
short data[] = {1,2,3,4,5,6,7,8,9,10};
short* ptr = data;
int n = sizeof(data);
printf("ptr size=%d,data=%I64d\n",sizeof(ptr),data);
for(int i=0;i<10;i++)
{
printf("data[%d]=%d,ptr=%I64d\n",i,*ptr,ptr);
ptr = ptr + 1;
}
}
输出如图:
可以看到,指针每次加1,是加2字节长度,即1个数组元素的大小。
(3) 指向4字节的数组指针:
void TestPointerSize()
{
int data[] = {1,2,3,4,5,6,7,8,9,10};
int* ptr = data;
int n = sizeof(data);
printf("ptr size=%d,data=%I64d\n",sizeof(ptr),data);
for(int i=0;i<10;i++)
{
printf("data[%d]=%d,ptr=%I64d\n",i,*ptr,ptr);
ptr = ptr + 1;
}
}
输出如图:
可以看到,指针每次加1,是加4字节长度,即1个数组元素的大小。
(4) 指向8字节的数组指针:
void TestPointerSize()
{
__int64 data[] = {1,2,3,4,5,6,7,8,9,10};
__int64* ptr = data;
int n = sizeof(data);
printf("ptr size=%I64d,data=%I64d\n",sizeof(ptr),data);
for(int i=0;i<10;i++)
{
printf("data[%d]=%I64d,ptr=%I64d\n",i,*ptr,ptr);
ptr = ptr + 1;
}
}
输出如图:
可以看到,指针每次加1,是加8字节长度,即1个数组元素的大小。
(1) 指向1字节的数组指针:
汇编声明一个数组:
.const
data_ byte 1,2,3,4,5,6,7,8,9,10
C++下声明一个访问数组元素的函数,并用汇编实现
extern "C" int GetArrayItem(int i,char* ptr);
汇编语言实现:
.code
GetArrayItem proc
; Make sure 'i' is valid
cmp ecx,0
jl InvalidIndex ;jump if i < 0
cmp ecx,[NumFibVals_]
jge InvalidIndex ;jump if i >= NumFibVals_
; Sign extend i for use in address calculations
;mov rax,offset data_ ;get
lea rbx,data_ ;取得数组的偏移地址,我们可以理解为取得数组的地址,也可换成offset伪指令
xor rax,rax
mov eax,ecx
imul eax,1 ;i的值乘以数据的大小,这里是1字节
movsxd rax,eax ;符号扩展到64位
add rbx,rax ;得到数组的偏移地址
mov eax,[rbx] ;取得偏移地址指向的内存存储的值
mov [rdx],eax ;将值复制到外部传入的指针所指示的内存地址
mov eax,1 ;set success return code
ret
InvalidIndex:
xor eax,eax ;set error return code
ret
GetArrayItem endp
end
调用代码:
void TestPointerSize()
{
char* ptr = (char*)malloc(sizeof(char));
for(int i=0;i<10;i++)
{
GetArrayItem(i,ptr);
printf("data[%d]=%d\n",i,*ptr);
}
free(ptr);
}
输出结果如图:
(2) 指向2字节的数组指针:
汇编声明一个数组:
.const
data_ word 2001,2002,2003,2004,2005,2006,2007,2008,2009,2010
汇编访问代码改一句:
imul rbx,2 ;i的值乘以数据的大小,现在这里是2字节
改调用函数:
extern "C" int GetArrayItem(int i,short* ptr);
调用代码:
void TestPointerSize()
{
short* ptr = (short*)malloc(sizeof(short));
for(int i=0;i<10;i++)
{
GetArrayItem(i,ptr);
printf("data[%d]=%d\n",i,*ptr);
}
free(ptr);
}
输出结果如图:
(3) 指向4字节的数组指针:
汇编声明一个数组:
.const
data_ dword 3001,3002,3003,3004,3005,3006,3007,3008,3009,3010
汇编访问代码改一句:
imul rbx,4 ;i的值乘以数据的大小,现在这里是4字节
改调用函数:
extern "C" int GetArrayItem(int i,int* ptr);
调用代码:
void TestPointerSize()
{
int* ptr = (int *)malloc(sizeof(int));
for(int i=0;i<10;i++)
{
GetArrayItem(i,ptr);
printf("data[%d]=%d\n",i,*ptr);
}
free(ptr);
}
输出结果如图:
(4) 指向8字节的数组指针:
汇编声明一个数组:
.const
data_ qword 8001,8002,8003,8004,8005,8006,8007,8008,8009,8010
汇编访问代码:
GetArrayItem proc
; Make sure 'i' is valid
cmp ecx,0
jl InvalidIndex ;jump if i < 0
cmp ecx,[NumFibVals_]
jge InvalidIndex ;jump if i >= NumFibVals_
; Sign extend i for use in address calculations
;mov rax,offset data_ ;get
lea rbx,data_ ;取得数组的偏移地址,我们可以理解为取得数组的地址,也可换成offset伪指令
xor rax,rax
mov eax,ecx
imul eax,8 ;i的值乘以数据的大小,这里是8字节
movsxd rax,eax ;符号扩展到64位
add rbx,rax ;得到数组的偏移地址
mov rax,[rbx] ;取得偏移地址指向的内存存储的值
mov [rdx],rax ;将值复制到外部传入的指针所指示的内存地址
mov eax,1 ;set success return code
ret
InvalidIndex:
xor eax,eax ;set error return code
ret
GetArrayItem endp
改调用函数:
extern "C" int GetArrayItem(int i,__int64* ptr);
调用代码:
void TestPointerSize()
{
__int64* ptr = (__int64*)malloc(sizeof(__int64));
for(int i=0;i<10;i++)
{
GetArrayItem(i,ptr);
printf("data[%d]=%d\n",i,*ptr);
}
free(ptr);
}
输出结果如图: