c指針通過編譯器實作彙編類似記憶體間接尋址功能,
程式設計語言的差異主要來自編譯器的解釋吧。
擔心圖檔久了失效,我都重新轉存的哈,希望造福對此感興趣的同學們。。
參考url:
<a href="http://bbs.pediy.com/showthread.php?t=105674">http://bbs.pediy.com/showthread.php?t=105674</a>
<a href="http://blog.csdn.net/willjet/article/details/5792689">http://blog.csdn.net/willjet/article/details/5792689</a>
<a href="http://bbs.21ic.com/icview-45502-1-1.html">http://bbs.21ic.com/icview-45502-1-1.html</a>
作者:亂雪 來源:hi.baidu.com/lu4nx
r.e.c--f22叫我來篇稿,我實在不知道寫啥,也很久沒寫過技術方面的東西了,剛看書時突然想到了寫指針,所有的c語書上都把指針描述得很抽象,是以,老規矩,結合調試器+彙編來了解它。
其實指針和彙編中的間接尋址很像,抽象點說,運用指針可以間接性地通路某變量内容。我說得太抽象了,扔代碼上來吧:
代碼:
這時lx的值就是10,可以加句printf("%d \n",lx);看到。
好了,進調試器來解釋吧。編譯環境vc6.0,調試器是vc6.0預設的調試器。需要觀衆有彙編語言的基礎。
先在int count = 10,lx;處下個斷點(右鍵——“insert/remove breakpoint”),然後按f5,進入調試狀态後,會自動在斷點處停下來,此時點在斷點行處右鍵——“go to disassembly”,來到彙編視窗。
這個時候斷點處的代碼如下:
0a是10的16進制,ebp-4是第一個變量count的位址,mov是傳送指令。此句的意思是把10指派給ebp-4,即count = 10。為了證明這一點,按一下f10單步運作,然後打開watch視窗,在“名稱”裡鍵入&count,就看到了count的位址,如圖:

在這裡順便說下,我們定義了三個變量,分别是count、lx和pointer,那麼分别對應的位址是ebp-4、ebp-8、ebp-0ch,因為整型變量占4位元組記憶體,每次ebp都會減少4。
根據剛才代碼中的順序,下一句是pointer = &count;,将pointer指向count的記憶體位址,我們看對應的彙編代碼:
前面說過,ebp-4是count變量的記憶體位址,為了直覺點,我把上面的彙編代碼改一下:
lea指令就是把一個記憶體變量有效的位址傳送給指定的寄存器。第一句lea eax,[ebp-4]是把count的位址傳到eax寄存器,根據剛才在watch視窗中看到的count位址是0012ff7c,那麼eax裡面的值就是0012ff7c。第二句mov dword ptr [ebp-0ch],eax是把eax中的值傳到ebp-0ch(pointer)中。很明顯,pointer = &count;這句代碼就等同于pointer = 0012ff7c;。為了直覺點,打開registers視窗,觀察寄存器。按三下f10執行三次單步運作,執行完mov dword ptr [ebp-0ch],eax指令,這個時候寄存器内容如圖:
看eax的值正好是count變量的記憶體位址0012ff7c。然後在watch視窗中輸入pointer,可以看到pointer的内容是0x0012ff7c,如圖:
說明pointer已經指到了count的記憶體位址了。
接下來看下一句代碼lx = *pointer;,對應的彙編代碼如下:
為了直覺,我改一下代碼:
這行代碼意思是取出pointer指向的内容賦給變量lx。彙編代碼中第一句mov ecx,dword ptr [ebp-0ch]意思是把ebp-0ch(pointer)中的值傳入到ecx寄存器中,剛才已經知道,pointer的内容是0x0012ff7c,那麼這個時候ecx的值就是0x0012ff7c。第二句mov edx,dword ptr [ecx]意思是取出ecx寄存器中的位址對應的值放入edx寄存器,此時edx寄存器的值就是count的值10了。最後再mov dword ptr [ebp-8],edx,把edx寄存器中的值傳到變量lx中。為了觀察到整個過程,我們單步運作,直到運作完mov edx,dword ptr [ecx]這句指令,然後觀察registers視窗,看到ecx的值是0012ff7c。ecx的值已經是count的記憶體位址了:
再單步運作一次,運作完指令mov edx,dword ptr [ecx],再看registers視窗,edx的值是0000000a,a是10的十六進制表示。
簡單總結下就是:首先将變量的位址放入寄存器中,然後再取出寄存器中存放位址對應的值。c指針的内幕就這樣,自己跟着調試一次代碼,就會了解了。如有不足之處歡迎一起讨論:)
c語言中指針和數組在編譯時的差別 例如:int a[10]和int *b,a[5]和*(b+5) 在編譯的時候差別是什麼? 經過反複的查資料和請教他人,最後在《c專家程式設計》裡找到了很好的答案。
1。編譯器對數組名和指針變量的處理方式 編譯器在編譯時會産生一個符号表,記錄了符号名和它的位址。對于指針變量,這顯然很好了解。而數組名就不那麼明顯了,它僅僅是一個符号而已,何來位址?編譯器是這樣處理的,它記錄了array[0]的位址;這和我們通常的了解也是一樣的。
2。帶下标形式的數組和指針尋址方式
(1)數組情形
char a[9]="abcdefgh"; ... c=a[i];
在編譯期,會在符号表中建立這樣一條記錄: name:a address:9980 要擷取a[i]的值分兩個步驟:
step 1:取得i的值并和9980相加
step 2:在記憶體位址(9980+i)處取其内容
(2)指針情形
char* p="abcdefgh"; ... c=p[i];
在編譯期,會在符号表中建立這樣一條記錄: name:p address:4624 要擷取p[i]的值分三個步驟:
step 1:在記憶體位址4624處取其内容,比如說“5081”
step 2:取得i的值并和5081相加 step 3:在記憶體位址(5081+i)取其内容
一、預備知識—程式的記憶體配置設定 一個由c/c++編譯的程式占用的記憶體分為以下幾個部分
1、棧區(stack)— 由編譯器自動配置設定釋放 ,存放函數的參數值,局部變量的值等。其 操作方式類似于資料結構中的棧。
2、堆區(heap) — 一般由程式員配置設定釋放, 若程式員不釋放,程式結束時可能由os回 收 。注意它與資料結構中的堆是兩回事,配置設定方式倒是類似于連結清單,呵呵。
3、全局區(靜态區)(static)—,全局變量和靜态變量的存儲是放在一塊的,初始化的 全局變量和靜态變量在一塊區域, 未初始化的全局變量和未初始化的靜态變量在相鄰的另 一塊區域。 - 程式結束後由系統釋放。
4、文字常量區 —常量字元串就是放在這裡的。 程式結束後由系統釋放
5、程式代碼區—存放函數體的二進制代碼。
二、例子程式
這是一個前輩寫的,非常詳細
//main.cpp
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main()
{
int b; 棧
char s[] = "abc"; 棧
char *p2; 棧
char *p3 = "123456"; 123456/0在常量區,p3在棧上。
static int c =0; 全局(靜态)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); 配置設定得來得10和20位元組的區域就在堆區。
strcpy(p1, "123456"); 123456/0放在常量區,編譯器可能會将它與p3所指向的"123456" 優化成一個地方。
}
2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運作時刻指派的;
而bbbbbbbbbbb是在編譯時就确定的;
但是,在以後的存取中,在棧上的數組比指針所指向的字元串(例如堆)快。 比如:
#include
void main()
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
對應的彙編代碼
10: a = c[1]; 00401067 8a 4d f1 mov cl,byte ptr [ebp-0fh] 0040106a 88 4d fc mov byte ptr [ebp-4],cl
11: a = p[1]; 0040106d 8b 55 ec mov edx,dword ptr [ebp-14h] 00401070 8a 42 01 mov al,byte ptr [edx+1] 00401073 88 45 fc mov byte ptr [ebp-4],al
第一種在讀取時直接就把字元串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到 edx中,再根據edx讀取字元,顯然慢了。
回複 #1 specter117 的文章
不知道你想要的是不是這個:
(1)對于順序通路的而言,數組比連結清單效率高。
(2)對于數組,間接通路(指數組名+下标)絕不比指針通路的效率高。
比如:
int i; int b[100];
數組通路;
for(i = 0; i < 100; i++)
{
b[i] = 0;
}
指針通路:
int *p = b;
{
*p++ = 0;
}
數組通路時,b等價于*(b + i) =*( (char *)b + i * sizeof(int) ) 指針通路時,*p++等價于*(p + 1) = *((char *)p + 1 * sizeof(int))
由于sizeof是在編譯時确定的,是以 b = *((char *) b + 4 * i) 而 *p++ = *((char *)p + 1) 間接通路有乘法運算,而指針通路隻有加法運算,
是以在這裡,間接通路沒有指針通路效率高。