1. 程式人生 > >嵌入式C語言之深談記憶體

嵌入式C語言之深談記憶體

記憶體:

    計算機程式=程式碼+資料(數字)
    用函式來類比:函式的形參就是代加工的資料(函式內還需要一些區域性變數),
                  函式本體就是程式,函式的返回值就是結果,函式體執行的過程就是過程。
    程式碼:函式
    資料:全域性變數,區域性變數。  
    
    記憶體管理:組合語言:沒有任何記憶體管理,彙編操作直接使用記憶體位置;
              C語言編譯器幫我們直接管理記憶體,我們通過編譯器的變數名訪問記憶體
              c++對於記憶體進行分裝,可以用new建立物件,為物件分派記憶體
              java c#不直接操作記憶體  通過虛擬機器幫我們操作記憶體。
              
              看中程式的效能,例如作業系統核心的編寫常用c/c++;
              在乎程式開發的速度時常用java/c#;
              
    從邏輯角度看記憶體:是一個東西,可以隨機訪問(給一個地址就可以訪問這個記憶體的地址,)
                      可以讀寫(也可以設定為只讀不寫)
                       天然用來存放變數(有了記憶體,C語言才能定義變數),
                       C語言一個變數就對應記憶體中的一個單元
    記憶體由無線多個記憶體單元組成,每個記憶體單元叫做記憶體地址;
    每個記憶體地址的和這個記憶體單元唯一對應且永久繫結。
    
    字和位是記憶體單元大小的單位,位(1bit) 位元組(8bit) 半字(一般是16bit) 字(一般是32bit)
    字  半字  雙字具體多少位有賴於平臺,不同的平臺,其位數不同
    在linux+arm軟硬體的系統內 字是32bit    

    記憶體的編址是以位元組為單位的。記憶體的地址空間的大小是固定的  為一個位元組(8bit)
    
    
資料型別:
    
    int型別的資料是整形資料,這個整體現在他和CPU本身的位寬是一樣的;
    資料型別用來定義變數,而變數需要儲存,運算在記憶體中,所以資料型別必須和記憶體相匹配才能最大程度上利用系統,得到最好的效率,最好的效能。即:32位系統中使用int
    型別的變數效率最高。    
    對齊訪問很配合硬體,所以效率很高,
    
    C語言中資料型別的作用:表示一個記憶體格子的長度和解析方法
    
    資料型別決定長度:我們一個記憶體地址(0x30000000)本來代表一個位元組長度,但是實際上我們可以通過給他一個型別(int),讓它有了長度(4),這樣本來這個記憶體地址的數字就從這個數字(0x30000000)就能代表以這個數字(0x30000000)開頭的n(4)個位元組的記憶體格子(0x30000000+0x30000001+0x300000002+0x300000003)。

   記憶體地址決定解析方法的含義:本身有一個記憶體地址,我們可以通過給這個記憶體地址不同的型別來指定這個記憶體單元格中二進位制數字的解析方法。
   一定的記憶體地址,通過不同的資料型別定義後可以有不用的二進位制解析方法,同時可以改變這個記憶體地址包括從改該記憶體格開始有多少個記憶體格,而存放的內容不會發生變化。
   
  關於型別(不管是普通的變數型別intfloat等,還是指標型別int*,float*等),型別只是對於後面的數字或者符號(代表的是記憶體地址)所象徵的記憶體的一種長度規定和解析方法規定而已。

  
簡單的資料結構:

  陣列:
      陣列管理記憶體和變數沒有什麼本質區別,只是符號的解析方法不一樣
      例如:int a    //編譯器分配4個位元組給a,並且把首地址和符號a繫結起來
         int a[10]//編譯器分配40個位元組給a[10],並把首地址和首元素a[0]繫結
   
  結構體:


         
      結構體可以很好的解決陣列內資料型別必須一致,且不能改變的缺陷,
      struct people   //people的的各種資料型別不同
      {
        int age;
        char name[20];
        int height;
      };
      含有不同的資料型別導致結構體不能直接訪問地址,而是要通過.a來訪問記憶體的地址。而陣列的資料型別固定,可以通過計算算出資料的記憶體地址從而可以直接訪問a[i]的記憶體地址。

  結構體內嵌指標實現面向物件:
  
      C語言是面向過程的,但是linux核心系統是面向物件的;
      sturct struct
      {
        int age ;     //普通變數
        void  (*pFunc)(void);   //函式指標  指向void Func (void)的函式
      }
      這樣包含了函式指標的結構體就類似於面向物件中的class,結構體中的變數就類似於class中的成員變數,結構體的函式指標相當於class中的成員方法。

  棧(stack)
     用來儲存區域性變數,管理記憶體,自動為變數分配記憶體空間。
      遵循先進後出原則,bittom固定在首地址,而top始終在最後一個記憶體地址的下一個地址。
     相對應的佇列:先進去的先出來,入口和出口都存在,從入口進入,出口出去
     
     區域性變數的是通過棧實現的。    
     棧由於反覆使用且不清零,所以定義區域性變數之後如果不進行初始化則區域性變數的值預設為上一次棧內的值。
  
  堆(heap):
     可以隨時申請,隨時釋放,大小快隨意的記憶體管理方式。
      堆記憶體是作業系統劃歸給堆管理器來管理的,然後向使用者(使用者系統)提供API(malloc和free)來使用堆記憶體。
      堆記憶體的申請和釋放都需要自己通過程式碼申請(malloc)和釋放(free),如果自己申請記憶體使用後沒有釋放,則這段記憶體就會丟失。
  
複雜資料結構:
    連結串列:節點的插入(前插,後插),節點的刪除,節點的查詢,節點的遍歷。