<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                【71.1 結構體的內存生效。】 上一節講到結構體有三道標準工序“造模”和“生成”和“調用”,那么,結構體在哪道工序的時候才會開始占用內存(或者說內存生效)?答案是在第二道工序“生成”(或者說定義)的時候才產生內存開銷。第一道工序僅“造模”不“生成”是不會產生內存的。什么意思呢?請看下面的例子。 第一種情況:僅“造模”不“生成”。 struct StructMould //“造模” { unsigned char u8Data\_A; unsigned char u8Data\_B; }; 分析:這種情況是沒有內存開銷的,盡管你已經寫下了數行代碼,但是C編譯器在翻譯此代碼的時候,它會識別到你偷工減料僅僅“造模”而不“生成”新變量,此時C編譯器會把你這段代碼忽略而過。 第二種情況:先“造模”再“生成”。 struct StructMould //“造模” { unsigned char u8Data\_A; unsigned char u8Data\_B; }; struct StructMould GtMould\_1; //“生成”一個變量GtMould\_1。占用2個字節內存 struct StructMould GtMould\_2; //“生成”一個變量GtMould\_2。占用2個字節內存 分析:這種情況才會占用內存。你“生成”變量越多,占用的內存就越大。像本例子,“生成”了兩個變量GtMould\_1和GtMould\_2,一個變量占用2個字節,兩個就一共占用了4個字節。結論:內存的占用是跟變量的“生成”有關。 【71.2 結構體的內存對齊。】 什么是對齊?為了確保內存的地址能整除某個“對齊倍數”(比如4)。比如以4為“對齊倍數”,在地址0存放一個變量a,因為地址0能整除“對齊倍數”4,所以符合“地址對齊”,接著往下再存放第二個變量b,緊接著的地址1不能整除“對齊倍數”4,此時,為了內存對齊,本來打算把變量b放到地址1的,現在就要更改挪到地址4才符合“地址對齊”,這就是內存對齊的含義。“對齊倍數”是什么?“對齊倍數”就是單片機的位數除以8。比如8位單片機的“對齊倍數”是1(8除以8),16位單片機是2(16除以8),32位單片機是4(32除以8)。本教程所用的單片機是8位的51內核單片機,因此“對齊倍數”是1。1是可以被任何整數整除的,因此,8位單片機在結構體的使用上被內存對齊的“干擾”是最小的。 為什么要對齊?單片機內部硬件層面一條指令處理的數據寬度是固定的,比如,因為一個字節是8位,所以,8位的單片機一次處理的數據寬度是1個字節(8除以8等于1),16位的單片機一次處理的數據寬度是2個字節(16位除以8位等于2),32位的單片機一次處理的數據寬度是4個字節(32位除以8位等于4),如果字節不對齊,本來單片機一個指令能處理的數據可能就要分解成2個指令甚至更多的指令,所以C編譯器為了讓單片機處于最佳狀態,在某些情況就會涉及內存對齊,結構體就涉及到內存對齊。 結構體的內存對齊表現在哪里呢?請看下面兩個例子: 第一個例子:8位單片機。 struct StructMould\_1 //“造模” { unsigned char u8Data; //一個unsigned char占用1個字節。 unsigned long u32Data; //一個unsigned long占用4個字節。 }; struct StructMould\_1 GtMould\_1; //占用多少個字節內存呢? 分析:GtMould\_1這個變量占用多少個內存字節呢?假設GtMould\_1的首地址是0,那么地址0就存放成員u8Data,u8Data占用1個字節,所以接下來的地址是1(0+1),問題來了,地址1能直接存放占用4個字節的成員u32Data嗎?因為8位單片機的“對齊倍數”是1(8除以8),那么地址1顯然是可以整除“對齊倍數”1的,因此,地址1是可以果斷存儲u32Data成員的。因此,GtMould\_1占用的總字節數是5(1+4),也就是u8Data和u32Data兩者所占字節數之和。 第二個例子:32位單片機。 struct StructMould\_1 //“造模” { unsigned char u8Data; //一個unsigned char占用1個字節。 unsigned long u32Data; //一個unsigned long占用4個字節。 }; struct StructMould\_1 GtMould\_1; //占用多少個字節內存呢? 分析:GtMould\_1這個變量占用多少個內存字節呢?假設GtMould\_1的首地址是0,那么地址0就存放成員u8Data,u8Data占用1個字節,所以接下來的地址是1(0+1),那么問題來了,地址1能直接存放占用4個字節的成員u32Data嗎?不能。因為32位單片機的“對齊倍數”是4(32除以8),那么地址1顯然是不可以整除“對齊倍數”4的,因此,就要把地址1更改挪到地址4這里才符合“地址對齊”,這樣,就意味著多插入了3個“填充的字節”,因此,GtMould\_1占用的總字節數是8(1+3+4),也就是“1個字節u8Data,3個填充字節,4個u32Data”三者所占字節數之和。那么問題又來了,如果把結構體內部成員u8Data和u32Data的位置順序更改一下,內存容量會有所改變嗎?位置順序更改后如下。 struct StructMould\_1 //“造模” { unsigned long u32Data; //一個unsigned long占用4個字節。 unsigned char u8Data; //一個unsigned char占用1個字節。 }; struct StructMould\_1 GtMould\_1; //占用多少個字節內存呢? 分析:更改u8Data和u32Data的位置順序后,u32Data在前u8Data在后,GtMould\_1這個變量占用多少個內存字節呢?假設GtMould\_1的首地址是0,那么地址0就存放成員u32Data,u32Data占用4個字節,所以接下來的地址是4(0+4),那么問題來了,地址4能直接存放占用1個字節的成員u8Data嗎?能。因為32位單片機的“對齊倍數”是4(32除以8),那么地址4顯然是可以整除“對齊倍數”4的,因此,地址4是可以果斷存儲u8Data的。那么,是不是GtMould\_1就占用5個字節呢?不是。因為結構體的內存對齊,還包括另外一條規定,那就是“一個結構體變量所占的內存總容量必須能整除該單片機的“對齊倍數”(單片機的位數除以8),如果不能,C編譯器就會擅自在最后一個成員的后面插入若干個“填充字節”來滿足這個規則”,根據這條規定,計算所得的總容量5是不能整除“對齊倍數”4的,必須再額外填充3個字節補足到8,才能整除“對齊倍數”4,因此,更改順序后,GtMould\_1還是占用8個字節(4+1+3),前4個字節是u32Data,中間1個字節是u8Data,后3個字節是“填充字節”。 因為本教程采用的是8位的51內核單片機,因此,在上述這個例子中,GtMould\_1所占的字節數是符合“第一個例子”的情況,也就是占用5個字節。內存對齊是遵守幾條嚴格的規則的,我只列出其中最關鍵的兩條給大家大致閱讀一下,有一個印象即可,不強求死記硬背,只需知道“結構體因為存在內存對齊,所以實際內存容量是有可能大于內部各成員類型字節數相加之和,尤其是16位或者32位這類單片機”就可以了。 第(1)條:結構體內部某個成員相對結構體首地址的偏移地址必須能整除該單片機的“對齊倍數”(單片機的位數除以8),如果不能,C編譯器就會擅自在各成員之間插入若干個“填充字節”來滿足這個規則。 第(2)條:一個結構體變量所占的內存總容量必須能整除該單片機的“對齊倍數”(單片機的位數除以8),如果不能,C編譯器就會擅自在最后一個成員的后面插入若干個“填充字節”來滿足這個規則。 【71.3 如何獲取某個結構體變量的內存容量?】 結構體存在內存對齊的問題,就說明它的內存占用情況不會像普通數組那樣一目了然,那么,我們編寫程序的時候怎么知道某個結構體變量占用了多少個字節數?答案是:用sizeof宏函數。比如: struct StructMould\_1 { unsigned long u32Data; unsigned char u8Data; }; struct StructMould\_1 GtMould\_1; unsigned long a; //此變量用來獲取結構體變量GtMould\_1所占用的字節總數 void main() //主函數 { a=sizeof(GtMould\_1); //利用宏函數sizeof獲取結構體變量所占用的字節總數 } 【71.4 結構體之間的賦值。】 結構體之間的賦值有兩種,第一種是成員之間“一對一”的賦值,第二種是整個結構體之間“面對面”的整體賦值。第一種成員賦值像普通變量賦值那樣,沒有那么多套路和忌諱,數據傳遞安全可靠。第二種整個結構體之間賦值在編程體驗上帶有“一鍵操作”的快感,但是要注意避開一些“雷區”,首先,整體賦值的前提是必須保證兩個結構體變量都是同一個“結構體模板”造出來的變量,不同“模板”的結構體變量之間禁止“整體賦值”,其次,哪怕是“同一個模板”的結構體變量,也并不是所有的“同模板結構體”變量都能實現整個結構體之間的直接賦值,只有在結構體內部成員比較簡單的情況下才適合“整體賦值”,如果結構體內部包含有“指針”或者“字符串”或者“其它結構體中的結構體”,這類情況就比較復雜,這時建議大家繞開有“雷區”的“整體賦值”而直接選用安全可靠的“成員賦值”。什么是“成員賦值”什么是“整體賦值”?請看下面兩個例子。 第一種:成員賦值。把結構體變量GtMould\_2\_A賦值給GtMould\_2\_B。 struct StructMould\_2 //“造模” { unsigned long u32Data; unsigned char u8Data; }; struct StructMould\_2 GtMould\_2\_A; //生成第1個結構體變量 struct StructMould\_2 GtMould\_2\_B //生成第2個結構體變量 void main() //主函數 { //先給GtMould\_2\_A賦初值。 GtMould\_2\_A.u32Data=1; GtMould\_2\_A.u8Data=2; //通過“成員賦值”,把結構體變量GtMould\_2\_A賦值給GtMould\_2\_B。 GtMould\_2\_B.u32Data=GtMould\_2\_A.u32Data; //成員之間“一對一”的賦值 GtMould\_2\_B.u8Data=GtMould\_2\_A.u8Data; //成員之間“一對一”的賦值 } 第二種:整體賦值。把結構體變量GtMould\_2\_A賦值給GtMould\_2\_B。 struct StructMould\_2 //“造模” { unsigned long u32Data; unsigned char u8Data; }; struct StructMould\_2 GtMould\_2\_A; //生成第1個結構體變量 struct StructMould\_2 GtMould\_2\_B //生成第2個結構體變量 void main() //主函數 { //先給GtMould\_2\_A賦初值。 GtMould\_2\_A.u32Data=1; GtMould\_2\_A.u8Data=2; //通過“整體賦值”,把結構體變量GtMould\_2\_A賦值給GtMould\_2\_B。 GtMould\_2\_B=GtMould\_2\_A; //整體之間“一次性”的賦值 } 上述例子中的整體賦值,是因為結構體內部的數據比較“簡單”,沒有包含“指針”或者“字符串”或者“其它結構體中的結構體”這類數據成員,如果包含這類成員,建議大家不要用整體賦值。比如遇到以下這類結構體就建議大家直接用安全可靠的“成員賦值”: struct StructMould //“造模” { unsigned char u8String\[\]=”String”; //字符串 unsigned char \*pu8Data; //指針 struct StructOtherMould GtOtherMould; //結構體中的結構體 }; 【71.5 例程練習和分析。】 現在編寫一個練習的程序: /\*---C語言學習區域的開始。-----------------------------------------------\*/ struct StructMould\_1 //“造模” { unsigned long u32Data; //一個unsigned long占用4個字節。 unsigned char u8Data; //一個unsigned char占用1個字節。 }; struct StructMould\_2 //“造模” { unsigned char u8Data; unsigned long u32Data; }; struct StructMould\_1 GtMould\_1; //占用多少個字節內存呢? struct StructMould\_2 GtMould\_2\_A; struct StructMould\_2 GtMould\_2\_B; unsigned long a; //此變量用來獲取結構體變量GtMould\_1所占用的字節總數 void main() //主函數 { a=sizeof(GtMould\_1); //利用宏函數sizeof獲取結構體變量GtMould\_1所占用的字節總數 //先給GtMould\_2\_A賦初值。 GtMould\_2\_A.u32Data=1; GtMould\_2\_A.u8Data=2; //通過“整體賦值”,把結構體變量GtMould\_2\_A賦值給GtMould\_2\_B。 GtMould\_2\_B=GtMould\_2\_A; //整體之間“一次性”的賦值 View(a); //把a發送到電腦端觀察 View(GtMould\_2\_B.u32Data); //把結構體成員GtMould\_2\_B.u32Data發送到電腦端觀察 View(GtMould\_2\_B.u8Data); //把結構體成員GtMould\_2\_B.u8Data發送到電腦端觀察 while(1) { } } /\*---C語言學習區域的結束。-----------------------------------------------\*/ 在電腦串口助手軟件上觀察到的程序執行現象如下: 開始... 第1個數 十進制:5 十六進制:5 二進制:101 第2個數 十進制:1 十六進制:1 二進制:1 第3個數 十進制:2 十六進制:2 二進制:10 分析: GtMould\_1所占的字節數a為5。 GtMould\_2\_B的結構體成員GtMould\_2\_B.u32Data為1。 GtMould\_2\_B的結構體成員GtMould\_2\_B.u8Data為2。 【71.6 如何在單片機上練習本章節C語言程序?】 直接復制前面章節中第十一節的模板程序,練習代碼時只需要更改“C語言學習區域”的代碼就可以了,其它部分的代碼不要動。編譯后,把程序下載進帶串口的51學習板,通過電腦端的串口助手軟件就可以觀察到不同的變量數值,詳細方法請看第十一節內容。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看