卡內基SSD6 System-Level Programming Exercise 1總結

來源:互聯網
上載者:User
        個人認為SSD6 Exercise 1是卡內基有史以來最經典的題目,本來想寫一篇大家都看得懂的長篇大論,無奈時間不夠,只好延續以往記流水帳的風格,把心得一條一條列出來。
        心得1.從彙編的層次去理解c語言傳值和傳地址的區別.看執行個體
  1. int main (int argc, char *argv[]) {
  2.     int start = 10;
  3.     int stride = 3;
  4.     int key3 = -1;
  5.     int key4 = 777;
  6.     char * msg1;
  7.     process_key34(&key3,&key4);  //傳地址    
  8.     msg1 = extract_message(start,stride);  //傳引用
  9.     return 0;
  10. }   

把這段代碼對應的彙編為:

  1. process_keys34(&key3, &key4);
  2.         lea    -0x28(%ebp),%eax            取key3的地址,即&key3
  3.         mov    %eax,0x4(%esp)            把&key3存到%esp+4
  4.         lea    -0x24(%ebp),%eax            取key4的地址,即&key4
  5.         mov    %eax,(%esp)                把&key4存到%esp
  6.         call   804858d                     調用函數process_keys34
  7. msg1 = extract_message1(start, stride);
  8.         mov    -0x10(%ebp),%eax        取實參start的值
  9.         mov    %eax,0x4(%esp)        得到start的副本,存到%esp+4
  10.         mov    -0x14(%ebp),%eax        取實參stride的值
  11.         mov    %eax,(%esp)            得到stride的副本,存到%esp
  12.         call   80485ba                        調用extract_message1方法
  13.         mov    %eax,-0xc(%ebp)        把傳回值賦給msg1    

調用process_keys34之前和之後的棧幀結構如下:
調用前main函數的棧幀:                            調用後main函數和process_keys34函數的棧幀:
        %ebp  <-----幀指標%ebp                                             %ebp 
        .......                                                                    .......
        start                                                                     start
        stride                                                                    stride
        key3                                                                     key3
        key4                                                                     key4
        msg1                                                                   msg1
         .......  <-----棧指標%esp                                            ........
                                                                                   &key3    <--------實參&key3
                                                                                   &key4    <--------實參&key4
                                                                                  返回地址
                                                                                   %ebp     <-----幀指標%ebp                                                 
                                                                                  局部變數
                                                                                   ......      <-----棧指標%esp   
返回地址是main函數調用process_keys34後繼續執行地方,如果我們想讓程式執行完process_keys34後跳到其他地方,就可以修改這個返回地址,要想修改返回地址的值,必須先得到儲存返回地址的那部分記憶體位址,在gdb裡面可以通過$ebp+4得到,而在程式裡面只能通過返回地址上面那個變數得到,即&key4對應的地址減1.理解了這點是解題的關鍵。

同理調用extrat_message之前和之後的棧幀結構如下:
調用前main函數的棧幀:                            調用後main函數和extrat_message函數的棧幀:
        %ebp  <-----幀指標%ebp                                             %ebp 
        .......                                                                    .......
        start                                                                     start
        stride                                                                    stride
        key3                                                                     key3
        key4                                                                     key4
        msg1                                                                   msg1
        .......    <-----棧指標%esp                                           ........
                                                                                   stride的副本    <--------實參stride
                                                                                   start的副本     <--------實參start
                                                                                  返回地址
                                                                                  
%ebp     <-----幀指標%ebp                                              
  
                                                                                  局部變數
                                                                                   ......      <-----棧指標%esp   

     心得2:指標符*和地址符&的混合計算
     1.  (char *) data + j 與 data + j
 data是一個int型的數組,data表示數組的首地址,我們知道地址其實是一個整數,任何地址都一樣,一個指向int的地址和一個指向char的地址本質上是一樣的,都是整數。但,c語言的編譯器會區別這兩種指標,如果指正ptr指向int,那麼 ptr + 1 的地址為 <ptr + 4>:ptr的地址加上4個位元組,如果ptr指向char,那麼 ptr + 1 的地址為 <ptr + 1>:ptr的地址加上1個位元組。當執行指標的加減法運算時,c語言會根據指標所指向的變數類型來確定需要加減多少地址。這裡先把data強制轉換成char類型的指標,那麼
(char *) data + j 的真真實位址是: <data + j>
 data + j 的真真實位址是:     <data + 4*j>
    2. *( (int *)&key3 + 1 ) + 1 與 *(&key3 + 1) + 1
其中 int a = 4; int * key3 = &a;所以 key3是一個指向int型的指標,也可以說key3的變數類型為(int *),那麼&key3就是指向指標的指標,變數類型為(int **),比key3多了一個星號,但兩者本質是一樣的,都是地址,都是一個整數,都佔4個位元組,且加1後都會在原來的地址上再加4個位元組,唯一的卻別就是這兩個地址存放變數的類型不同,*( (int *)&key3 + 1 )是一個int型的值,而
*(&key3 + 1)是一個(int *)的值,兩者分別加1運算後,前者加1,後者加4,這就是區別。
    3.指標和地址的區別
指標是變數,地址是值,指標的值本質上是一個地址

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.