程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 用匯編的眼光看C++(之指針1)

用匯編的眼光看C++(之指針1)

編輯:C++入門知識

 

【 聲明:版權所有,歡迎轉載,請勿用於商業用途。  聯系信箱:feixiaoxing @163.com】

 

 

 

    指針是我們在C/C++中經常遇到的一種數據類型。指針用的好,可以提高代碼的可讀性;但是如果使用不恰當,反而會造成很大的麻煩。指針,也就是指向某一種數據類型的地址。這種類型很多,它可以是編程語言自帶的類型,比如說int、long、short、char、float、double、int;也可是是指向某一種自定義數據類型,可以使union、struct或者是class;甚至指向的數據類型本身即是指針,比如說int*、char*、short**;當然指針還可以是指向一片內存,表示具有一定長度的起始地址,比如說int(*pData)[4];最後,指針還可以是函數指針,直接指向函數運行的第一個字節。

 

    (1)普通數據類型指針

 

    普通數據類型指針相對概念比較簡單,它表示指向的區域就是普通數據類型的空間。我們可以看下面一段示例代碼:

 

 

43:       int  m = 10; 

004012F8   mov         dword ptr [ebp-4],0Ah 

44:       char* p = (char*) &m; 

004012FF   lea         eax,[ebp-4] 

00401302   mov         dword ptr [ebp-8],eax 

45:       float* f = (float*) &m; 

00401305   lea         ecx,[ebp-4] 

00401308   mov         dword ptr [ebp-0Ch],ecx 

46:       short* s = (short*) &m; 

0040130B   lea         edx,[ebp-4] 

0040130E   mov         dword ptr [ebp-10h],edx 

47:       *p = 2; 

00401311   mov         eax,dword ptr [ebp-8] 

00401314   mov         byte ptr [eax],2 

48:       *f = 2.4f; 

00401317   mov         ecx,dword ptr [ebp-0Ch] 

0040131A   mov         dword ptr [ecx],4019999Ah 

49:       *s = 10; 

00401320   mov         edx,dword ptr [ebp-10h] 

00401323   mov         word ptr [edx],offset process+46h (00401326) 

    上面的一段代碼出現了四種數據類型,三種指針,我們可以一一梳理一下。m、p、f、s都是函數內部的臨時變量,因為指針也是一種數據類型,它保存的數據不再是一種char或者是short、int數據,而是一種地址。所以我們對p、f、s進行復制的時候,都是把m的地址一一拷貝給他們的。所以雖然指針類型不同,實際上p、f、s的數值是一樣的。下面對指針指向的空間進行數據賦值的時候,就和指針類型相關了。一般來說,如果指針為char類型,那麼計算就局限在指針指向的那一個字節裡面;如果指針是int類型,那麼運算的范圍就是指針指向的連續4個字節;當然如果指針是數據結構體或者是class類型,那麼指針操作的內存區域就更大了。所以,我們返回到代碼的時候發現,*p=2只是操作了一個byte,*f=2.4f的時候,操作的是四個byte、也就是dword,*s=10的時候,賦值的就是一個word,這裡0x401326處其實就是數據0x00 0A。函數內的變量進過這一番折騰之後,m數值還是10嗎?大家可以好好思考一下?(其實是0x4019000a)

    (2)函數類型指針

 

    下面是一段有趣的代碼,可以查看函數的地址。

 

 

void add() 

    printf("hello!\n"); 

 

 

void process(int* q) 

    int* address = (int*)add; 

 

    __asm{ 

        call address 

    } 

    這段代碼使用了嵌入式匯編,但是理解上面沒有什麼困難,感興趣的同學可以直接拷貝到VC上面進行編譯,當然還要加上頭文件和main函數。通過代碼,我們可以發現其實address就是一個地址,call address其實和call add是一樣的。

 

    (3)指針的指針

 

    指針的指針,其實就是說我們指針指向的數據類型本身就是指針。但是,總之一句,指針是地址,那麼指向地址數據的指針本身也是地址。

 

 

46:       int* pp = &p; 

004012FF   lea         eax,[ebp-4] 

00401302   mov         dword ptr [ebp-8],eax 

47:       int** ppp = &pp; 

00401305   lea         ecx,[ebp-8] 

00401308   mov         dword ptr [ebp-0Ch],ecx 

48:       int*** pppp = &ppp; 

0040130B   lea         edx,[ebp-0Ch] 

0040130E   mov         dword ptr [ebp-10h],edx 

49:       assert(sizeof(p) == 4); 

50:       assert(sizeof(pp) == 4); 

51:       assert(sizeof(ppp) == 4); 

52:       assert(sizeof(ppp) == 4); 

    指針是一種保存地址的數據類型,那麼指針的指針也是一種地址數據,保存的也是地址。以此類推,指針的指針的指針呢。。。。。。上面的代碼已經清楚地說明了這一點。雖然pp、ppp、pppp自身的意義有所差別,但是他們保存的數據卻很簡單,也就是堆棧的地址。pppp->ppp->pp->p,大家如果看懂了這個關系,就不會覺得指針很復雜了。如果還是不甚了了,可以把指針內容和指針地址分別打印出來,就會發現他們的區別了。下面就是打印的結果:

 

 

p = 0xa,&p = 0x12ff20 

pp = 0x12ff20,&pp = 0x12ff1C 

ppp = 0x12ff1C,&ppp = 0x12ff18 

pppp = 0x12ff18,&pppp = 0x12ff14 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved