指针的几个小问题

本来一切都安好的, 听唐老师讲了几节指针的课, 发现有很多问题过去并不是很清晰啊, 还有一些认为想当然的问题也遇到了挑战. 最近做笔记比较少. 写下本文权当笔记吧!

前几天唐老师一直讨论的指针是无符号还是有符号数也是比较郁闷, 我问了下小浩, 他说指针应该是无符号的, 不然就不能够指向内存的高2G. 我觉得这个说的很有道理, 另外一个我自己在比较两个指针的时候发现用的是JA, JB所以我也断定这个指针应该内部当做无符号来对待的,但是唐老师提到两个指针做减法的问题, 他说两个指针在做减法的时候再和某个数比较的时候用的却是有符号. 具体这个东西是有符号还是无符号的, 觉得只能让写编译器的人给个答案了!

另外昨天也接触到指针的一个特殊用法, 我倒. 以前居然从没有见过. 类似于这种形式:
int*** (**p)[5][5]
原来对于这个指针数组还是有点明白的, 但是对于这个用一个指针指向数组, 然后数组里面存放的又全是指针, 这个应该叫什么?指针的指针数组?? 以前也没有见过哪里使用过这种语法! 另外我咋一眼看上去觉得这个东西应该是数组, 然后发现其只是一个指针.指针而已. 占用4个字节空间.

今天早上唐老师又拿了几道题目过来测试, 反写汇编代码, 使我大受打击, 我倒.. 这边就贴代码, 然后跟着代码注释. 以前没有来这边一直没有用过3个*的变量, 来这边以后我倒, 起步价5个*… 也不知道用没有用处!

typedef int*** PP;                        //这是命名多级指针的语法.
typedef int*** PARRY[10][10];            //给指针数组取别名
typedef int*** (*PPP)[10][10];            //这是对指向多级指针的数组的的指针语法
typedef PSTUDENT (*PST)[10][10];        //这是指向结构的别名
typedef int (__cdecl *PFUNCTION)(int,int);//这是给函数指针取别名
 

这边是C语言代码. 看看反汇编出来的都是什么东西:

int funciton1(int*** (*p)[3][4][5], int a[][7][8][9] ) {
	p++;
	*p++;

	p[2] [3][4][5] [6][7][8] = 50;

	a++;
	((((a[2]+3)[4])+5)[6])[5] = 10;

	*(&a) += 1;
	return 0;
}

int funciton2(int a[6][7][8][9],int b)
{
	int j;
	int****** (******p)[10][8][6];
	a++;
	a[3][2][1][4] ='A';
	p[6][5][4][3][2] [1][3][2][1] [1][2][3][4][5][6] = 2;
	return 0;
}

int main() {

	int*** a[3][4][5];
	int b[6][7][8][9];

	funciton1( &a, b );
	funciton2( b, 10 );
	return 0;
}

总共两个函数了. 看看两个函数反汇编出来的结果:

;============================================================================
_funciton1 proc
	push	ebp
	mov	ebp, esp
;============================================================================
;	p++
;	这里加了240是这样计算出来的, p本身是一个int*** (*p)[3][4][5]类型的变量,
;	按照唐老师的方法, 去掉一个*看类型那么就是int*** (p)[3][4][5]那么, 也就是
;	一个数组的大小了, (3*4*5)*4 = 240 所以p++是加240
;============================================================================
	mov	eax, dword ptr _p$[ebp]
	add	eax, 240				; 000000f0h
	mov	dword ptr _p$[ebp], eax
;============================================================================
;	*p++
;	这里这个问题一直是我以前所困扰的, 我以前一直认为*p++是p所指向的内容++
;	但是很明显也是加了240, 主要的问题只有一个, 就是++的运算符级别比*高,
;	所以要先和++结合, 剩下的就和我们声明的int变量 a++一样了..
;============================================================================
	mov	ecx, dword ptr _p$[ebp]
	add	ecx, 240				; 000000f0h
	mov	dword ptr _p$[ebp], ecx
;============================================================================
;	p[2][3][4][5][6][7][8] = 50;
;	上面声明p是int*** (*p)[3][4][5]类型, 使用的时候用的全是[], 有点郁闷.
;	那么或许我们换成这种形式可以看更清楚一些.前面这种是全*访问,
;	后面这种才是应该的正统访问方式

;	(*(*(* (*(*(* (*(p+2) +3)+4)+5) +6)+7)+8)) = 50	;全*

;	*(*(* ((*(p+2)) [3][4][5] +6)+7)+8) = 50;	;正统访问方式
;820 = ( sizeof(int)*(3*4*5)*2 ) + (sizeof(int)*(4*5))*3 + (sizeof(int)*5*4)+ sizeof(int***)*5
;	所以以前认为[]和*没有理解好, 虽然这里每种方式都可以访问, 生成的汇编
;	代码也是一样的, 但是自己要注意区分, 这里的3, 4, 5都是属于数组的, 前面的
;	2是属于*p的, 其大小就是整个的数组大小.
;============================================================================
	mov	edx, dword ptr _p$[ebp]
	mov	eax, dword ptr [edx+820]

	mov	ecx, dword ptr [eax+24]
	mov	edx, dword ptr [ecx+28]
	mov	dword ptr [edx+32], 50			; 00000032h
;============================================================================
	;a++
	;a++的话由于a其实只是一个这种类型的指针 int a* [7][8][9]
	;那么a++的话其实就是 a += (7*8*9)*4		;2016
;============================================================================
	mov	eax, dword ptr _a$[ebp]
	add	eax, 2016				; 000007e0h
	mov	dword ptr _a$[ebp], eax
;============================================================================
	;((((a[2]+3)[4])+5)[6])[5] = 10;
;	那么这句代码其实是这种形式了.
;	a[2][7][11][5] = 10
;	所以计算出来应该是这样的
;	a + 2*(7*8*9)*4 + 7*(8*9)*4 + 11*(9*4) + 5*4	;6464
;============================================================================
	mov	ecx, dword ptr _a$[ebp]
	mov	dword ptr [ecx+6464], 10		; 0000000ah
;============================================================================
	;*(&a) += 1
;	这里再一次证明了数组只是一个指针名称, 传递参数里面.是没有数组的!
;	当然这里是一句废话, *&同时出现是会抵消的, 所以其实是这句
;	a += 1
;============================================================================
	mov	edx, dword ptr _a$[ebp]
	add	edx, 2016				; 000007e0h
	mov	dword ptr _a$[ebp], edx

	xor	eax, eax
	pop	ebp
	ret	0
_funciton1 endp
;============================================================================
	;这是function2生成的代码
;============================================================================
_funciton2 proc
	push	ebp
	mov	ebp, esp
;============================================================================
;	这里是代码有少量优化的效果, push ecx而不用sub esp, 4这句上面代码有体现
;	a += ((7*8*9)*4)				;2016
;============================================================================
;	a++;
	push	ecx
	mov	eax, dword ptr _a$[ebp]
	add	eax, 2016				; 000007e0h
	mov	dword ptr _a$[ebp], eax
;============================================================================
	;这里是以前正常的把带*参数当成数组来用的例子, 其实是这种形式
	;a + 3*(7*8*9)*4 + 2*(8*9)*4 + 1*(9*4) + 4*1*4	;6676
;============================================================================
	;a[3][2][1][4] ='A';
	mov	ecx, dword ptr _a$[ebp]
	mov	dword ptr [ecx+6676], 65		; 00000041h
;============================================================================
	;p[6][5][4][3][2] [1][3][2][1] [1][2][3][4][5][6] = 2;
	;其实下面这个表达式才是正统的写法.
	;*(*(*(*(*(*( ((*(*(*(*(*(p+6)+5)+4)+3)+2)) [1][3][2][1] )+1)+2)+3)+4)+5)+6) = 2;
	;或者换成全*方式
	;*(*(*(*(*(*( (*(*(*(*(*(*(*(*(*(p+6)+5)+4)+3)+2) +1)+3)+2)+1) )+1)+2)+3)+4)+5)+6) = 2;
	;主要就是要区分好数组和指针之间的关系, 虽然可以套用. 但是自己心里一定
	;要明白.目前是什么..
	;[1][3][2][1] = 1*(10*8*6)*4 + 3*(8*6)*4 + 2*(6*4)+1*4	;2548
;============================================================================
	mov	edx, dword ptr _p$[ebp]
	mov	eax, dword ptr [edx+24]
	mov	ecx, dword ptr [eax+20]
	mov	edx, dword ptr [ecx+16]
	mov	eax, dword ptr [edx+12]
	mov	ecx, dword ptr [eax+8]
	mov	edx, dword ptr [ecx+2548]
	mov	eax, dword ptr [edx+4]
	mov	ecx, dword ptr [eax+8]
	mov	edx, dword ptr [ecx+12]
	mov	eax, dword ptr [edx+16]
	mov	ecx, dword ptr [eax+20]
	mov	dword ptr [ecx+24], 2
;============================================================================
	xor	eax, eax
	mov	esp, ebp
	pop	ebp
	ret	0
_funciton2 endp

 

网友评论:

  1. Garrett Dalenberg 说:

    hi, has become a fashion designer must have a very high confidence,

发表评论

发表评论前,请选对水果: 菠萝