指針
什么是指針
一般關(guān)于指針的解釋都離不開地址。這里先暫且忘記這個概念
指針其實也是一種數(shù)據(jù)類型,和先前學(xué)習(xí)的int float等數(shù)據(jù)類型沒有實質(zhì)上的區(qū)別,只不過這個數(shù)據(jù)類型是在先前學(xué)習(xí)的所有數(shù)據(jù)類型后面加上若干個*號,如char *,int *等等,這種數(shù)據(jù)類型被稱為指針
- 任意類型后面都可以加上*號,使其成為新的指針數(shù)據(jù)類型
- *可以是任意多個
指針的聲明
指針的聲明其實在前面介紹什么是指針的時候就已經(jīng)講到了,例子如下:
struct S1{
int a;
};
void function(){
char* a;
short** b;
int*** c;
long**** d;
_int64***** e;
float****** f;
double******* g;
S1******** s1;
}
可以看到所有的其它數(shù)據(jù)類型(包括結(jié)構(gòu)體)后面加上若干個*后就是所謂的指針了
推薦的聲明方式如上
但也可以這樣將*放在變量前面,但不推薦,因為這樣相當(dāng)于將這個數(shù)據(jù)類型拆開了,不利于理解
struct S1{
int a;
};
void function(){
char *a;
short **b;
int ***c;
long ****d;
_int64 *****e;
float ******f;
double *******g;
S1 ********s1;
}
指針的賦值
在說指針的賦值之前先看看先前普通變量的賦值
普通變量的賦值貌似是直接使用 變量=值即可,但其實是編譯器簡化了賦值的步驟,實際上在賦值前本應(yīng)該加上要賦值類型
例子如下:
void function(){
int a;
a=610;
a=(int)610;
}
現(xiàn)在再來看指針的賦值
void function(){
char* a;
a=(char*) 610;
int** b;
b=(int**) 610;
}
在要賦的值前面加上指針的類型即可,貌似和普通變量的賦值并無太大差別,此時也注意到這里的指針也和地址沒有什么關(guān)聯(lián)
指針的的類型轉(zhuǎn)換這里暫且不提
指針的數(shù)據(jù)寬度
研究數(shù)據(jù)寬度方法
先前研究過其它基本變量的數(shù)據(jù)寬度,會發(fā)現(xiàn)char、short、int都是按照4字節(jié)來分配的(內(nèi)存對齊),但實際使用的情況下則是按照其原本類型的數(shù)據(jù)寬度來賦值或進(jìn)行其它操作的
如:
void function(){
char a;
short b;
int c;
a=1;
b=2;
c=3;
}
其對應(yīng)的反匯編代碼為:
11: void function(){
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,4Ch
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-4Ch]
0040101C mov ecx,13h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
12: char a;
13: short b;
14: int c;
15: a=1;
00401028 mov byte ptr [ebp-4],1
16: b=2;
0040102C mov word ptr [ebp-8],offset function+20h (00401030)
17: c=3;
00401032 mov dword ptr [ebp-0Ch],3
18: }
00401039 pop edi
0040103A pop esi
0040103B pop ebx
0040103C mov esp,ebp
0040103E pop ebp
0040103F ret
可以注意到此時提升的堆棧為4Ch,而默認(rèn)(空函數(shù)時)提升的堆棧為40h
00401013 sub esp,4Ch
于是此時為三個變量分配的空間是:4Ch-40h=0xC=12=3×4,即為char short int都分配了4個字節(jié)
但在這三個變量賦值的時候展現(xiàn)出來的就是其原本的數(shù)據(jù)類型寬度了
15: a=1;
00401028 mov byte ptr [ebp-4],1
在char類型的a中的賦值寬度是 byte,1字節(jié)
16: b=2;
0040102C mov word ptr [ebp-8],offset function+20h (00401030)
在int類型的c中的賦值寬度是dword,4字節(jié)
研究指針數(shù)據(jù)寬度
于是如法炮制,按照前面的方法來研究指針的數(shù)據(jù)寬度
在前面的數(shù)據(jù)類型后添加*,使其成為指針類型
void function(){
char* a;
short* b;
int* c;
a=(char*) 1;
b= (short*) 2;
c=(int*) 3;
}
其對應(yīng)的反匯編代碼為
11: void function(){
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,4Ch
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-4Ch]
0040101C mov ecx,13h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
12: char* a;
13: short* b;
14: int* c;
15: a=(char*) 1;
00401028 mov dword ptr [ebp-4],1
16: b= (short*) 2;
0040102F mov dword ptr [ebp-8],2
17: c=(int*) 3;
00401036 mov dword ptr [ebp-0Ch],3
18: }
0040103D pop edi
0040103E pop esi
0040103F pop ebx
00401040 mov esp,ebp
00401042 pop ebp
00401043 ret
直接觀察對應(yīng)的賦值語句:
15: a=(char*) 1;
00401028 mov dword ptr [ebp-4],1
16: b= (short*) 2;
0040102F mov dword ptr [ebp-8],2
17: c=(int*) 3;
00401036 mov dword ptr [ebp-0Ch],3
可以看到,所有賦值的寬度都為dowrd,說明無論是char*、short、int\其數(shù)據(jù)寬度都為4字節(jié)
可以使用同樣的方法研究float、double、struct等其它數(shù)據(jù)類型
并且在這里會注意到,指針類型的賦值和非指針類型的賦值在反匯編中并沒有什么區(qū)別
總結(jié)
無論是什么類型,在其后面加上(無論加幾個\都一樣)后其數(shù)據(jù)寬度都變?yōu)?字節(jié)
指針的加減
例子
指針類型也支持加減的操作,但不支持乘和除(編譯器決定的),來看例子:
#include "stdafx.h"
void function(){
char* a;
short* b;
int* c;
a=(char*) 1;
b= (short*) 2;
c=(int*) 3;
a++;
b++;
c++;
printf("a:%d\t b:%d\tc:%d\n",a,b,c);
}
int main(int argc, char* argv[])
{
function();
return 0;
}
運(yùn)行結(jié)果
分析
這里會觀察到結(jié)果并不是想象中的2,3,4;而是2,4,7
細(xì)心的小伙伴肯定發(fā)現(xiàn)了:
- 2 = 1 + 1 (char數(shù)據(jù)寬度為1字節(jié))
- 4 = 2 + 2 (short數(shù)據(jù)寬度為2字節(jié))
- 7 = 3 + 4 (int數(shù)據(jù)寬度為4字節(jié))
結(jié)果是加上了原本各自的數(shù)據(jù)類型的寬度
拓展例子
前面只是都是一級指針,現(xiàn)在將指針換為二級指針:
void function(){
char** a;
short** b;
int** c;
a=(char**) 1;
b= (short**) 2;
c=(int**) 3;
a++;
b++;
c++;
printf("a:%d\t b:%d\tc:%d\n",a,b,c);
}
運(yùn)行結(jié)果
分析
此時的結(jié)果為:
-
5= 1 + 4 (char* 數(shù)據(jù)寬度為4字節(jié))
-
6= 2 + 4 (short* 數(shù)據(jù)寬度為4字節(jié))
-
7 = 3 + 4 (int* 數(shù)據(jù)寬度為4字節(jié))
結(jié)果為加上 去掉一個*后的數(shù)據(jù)寬度
拓展例子二
前面的加法操作都只增加了1,現(xiàn)在再來查看增加大于1時的情況
void function(){
char* a;
short* b;
int* c;
a=(char*) 1;
b= (short*) 2;
c=(int*) 3;
a=a+5;
b=b+5;
c=c+5;
printf("a:%d\t b:%d\tc:%d\n",a,b,c);
}
運(yùn)行結(jié)果
分析
此時的結(jié)果為:
- 6= 1 + 5*1 (char 數(shù)據(jù)寬度為1字節(jié))
- 12= 2 + 5*2 (short 數(shù)據(jù)寬度為2字節(jié))
- 23 = 3 + 5*4 (int 數(shù)據(jù)寬度為4字節(jié))
結(jié)果為加上 去掉一個*后的數(shù)據(jù)寬度 × 增加的數(shù)值
總結(jié)
無論是指針的加亦或是減(這里只演示了加法,但減法同理),其加或減的單位為去掉一個*后的數(shù)據(jù)寬度
也就是實際增減的數(shù)值=去掉一個*后的數(shù)據(jù)寬度 × 增減的數(shù)值
指針類型相減
前面提到的指針的加減都是同一個指針里的加減,但指針之間其實也支持相減操作(不支持相加)
但指針之間的加減要求指針的類型必須一致,即char類型只能和char類型相加減,不能和char**或其它類型相加減
例子
void function(){
char* a;
char* b;
short* c;
short* d;
int* e;
int* f;
a=(char*) 200;
b=(char*) 100;
c=(short*) 200;
d=(short*) 100;
e=(int*) 200;
f=(int*) 100;
printf("%d\n",a-b);
printf("%d\n",c-d);
printf("%d\n",e-f);
}
運(yùn)行結(jié)果
分析
此時的結(jié)果為:
- 100 = (200 - 100)/1(char 數(shù)據(jù)寬度為1字節(jié))
- 50 = (200 - 100)/2 (short 數(shù)據(jù)寬度為2字節(jié))
- 25 = (200 - 100)/4 (int 數(shù)據(jù)寬度為4字節(jié))
結(jié)果為相減完后再除以 原本各自的數(shù)據(jù)寬度
擴(kuò)展例子
前面只是都是一級指針,現(xiàn)在將指針換為四級指針:
void function(){
char**** a;
char**** b;
short**** c;
short**** d;
int**** e;
int**** f;
a=(char****) 200;
b=(char****) 100;
c=(short****) 200;
d=(short****) 100;
e=(int****) 200;
f=(int****) 100;
printf("%d\n",a-b);
printf("%d\n",c-d);
printf("%d\n",e-f);
}
運(yùn)行結(jié)果
分析
此時的結(jié)果為:
- 25 = (200 - 100)/4(char*** 數(shù)據(jù)寬度為4字節(jié))
- 25 = (200 - 100)/4 (short*** 數(shù)據(jù)寬度為4字節(jié))
- 25 = (200 - 100)/4 (int*** 數(shù)據(jù)寬度為4字節(jié))
結(jié)果為相減后再除以 去掉一個*后的數(shù)據(jù)寬度
總結(jié)
指針之間的減法,其結(jié)果為相減后再除以去掉一個*后的數(shù)據(jù)寬度
指針之間的比較
指針之間也支持相互比較,但也和上面指針類型相減一樣,要求指針類型一致
例子
void function(){
char**** a;
char**** b;
a=(char****) 200;
b=(char****) 100;
if (a>b)
{
printf("a>b\n");
}else{
printf("a<=b\n");
}
}
運(yùn)行結(jié)果
結(jié)論
相同類型的指針之間是支持大小比較的
總結(jié)
-
指針的數(shù)據(jù)寬度為4字節(jié),或者說:無論是什么類型,在其后面加上(無論加幾個\都一樣)后其數(shù)據(jù)寬度都變?yōu)?字節(jié)
-
指針數(shù)值支持進(jìn)行加減,加減的結(jié)果=去掉一個*后的數(shù)據(jù)寬度 × 增減的數(shù)值
-
指針之間支持減法但不支持加法,其結(jié)果為相減后再除以去掉一個*后的數(shù)據(jù)寬度文章來源:http://www.zghlxwxcb.cn/news/detail-546325.html
-
指針之間支持比較大小,但要求進(jìn)行比較的兩個指針為相同類型文章來源地址http://www.zghlxwxcb.cn/news/detail-546325.html
到了這里,關(guān)于Windows逆向安全(一)之基礎(chǔ)知識(十四)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!