<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # 字節對齊 在用sizeof計算結構體占用的空間的時候,不是簡單把所有元素相加的,這里涉及到內存字節對齊的問題 從理論上來講,對于任何變量都可以從任何地址訪問,但是事實不是如此,實際上訪問特定類型的變量只能在特定的地址訪問,這就需要各個變量在空間上按照一定的規則排列而不是簡單的順序排列,這就是內存對齊 ![](https://box.kancloud.cn/33f8218998f2cc48d28ab2639601da8f_1313x304.png) cpu雖然每次讀取的單位是字節,但是一次是讀取一個塊,所以有些硬件設備不允許放在內存的奇數位上 內存對齊是操作系統為了提高訪問內存的策略.操作系統在訪問內存的時候,每次讀取一定長度(這個長度是操作系統的對齊數,或者默認對齊數的整數倍).如果沒有對齊,為了訪問一個變量可能產生二次訪問 * 提高存取數據的速度.比如有的平臺每次都是從偶地址讀取數據,對于一個int地址的變量.若從偶地址單元處存放,則需一個讀取周期即可讀取該變量,但是若從奇地址單元處存放,則需要2個讀取周期讀取變量 * 某些平臺只能在特定的地址訪問特定類型的數據,否則拋出硬件異常給操作系統 ## 如何內存對齊 * 對于標準數據類型,它的地址只要是它的長度的整數倍 * 對于非標準類型,比如結構體,要遵循一下對齊原則 1. 數組成員對齊規則.第一個數組成員應該放在offset為0的地方,以后每個數組成員應該在offset為min(當前成員的大小, #paragama pack(n))整數倍的地方開始(比如int在32位機器為4字節, #paragam pack(2),那么從2的倍數地方開始存儲) 2. 結構體總的大小,也就是sizeof的結果,必須是min(結構體內部最大成員, #paragama pack(n))的整數倍,不足要補齊 3. 結構體作為成員的對齊規則,如果一個結構體B里嵌套了另一個結構體A,還是以最大成員類型的大小對齊,但是結構體A的起點為A內部最大成員的整數倍地方(struct B里有struct A,A里有char,int,double等成員,那A應該從8的整數倍開始存儲),結構體A中的成員對齊規則仍滿足原則1和原則2 ## 手動對齊模式 ~~~ #pragma pack(show) 顯示當前packing alignment的字節數,以warning message的形式被顯示 #pragma pack(push) 將當前指定的packing alignment數組進行壓棧操作,這里的棧是the internal compiler stack,同時設置當前的packing alignment為n,如果n沒有指定,則將當前的packing alignment數組壓棧 #pragma pack(pop) 從internal compiler stack中刪除最頂端的reaord,如果沒有指定n,則當前棧頂record即為新的packing alignement數值.如果指定了n,則n成為新的packing alignment值 #pragma pack(n) 指定packing的數值,以字節為單位,缺省數值是8,合法數值分別是1,2,4,8,16 ~~~ ## 為何需要對齊 計算機內存是以字節(Byte)為單位劃分的,理論上CPU可以訪問任意編號的字節,但實際情況并非如此。 CPU 通過地址總線來訪問內存,一次能處理幾個字節的數據,就命令地址總線讀取幾個字節的數據。32 位的 CPU 一次可以處理4個字節的數據,那么每次就從內存讀取4個字節的數據;少了浪費主頻,多了沒有用。64位的處理器也是這個道理,每次讀取8個字節。 以32位的CPU為例,實際尋址的步長為4個字節,也就是只對編號為 4 的倍數的內存尋址,例如 0、4、8、12、1000 等,而不會對編號為 1、3、11、1001 的內存尋址。如下圖所示: ![](https://box.kancloud.cn/db212cd6247c38402d384c87290877c8_500x87.png) 樣做可以以最快的速度尋址:不遺漏一個字節,也不重復對一個字節尋址。 對于程序來說,一個變量最好位于一個尋址步長的范圍內,這樣一次就可以讀取到變量的值;如果跨步長存儲,就需要讀取兩次,然后再拼接數據,效率顯然降低了。 例如一個 int 類型的數據,如果地址為 8,那么很好辦,對編號為 8 的內存尋址一次就可以。如果編號為 10,就比較麻煩,CPU需要先對編號為 8 的內存尋址,讀取4個字節,得到該數據的前半部分,然后再對編號為 12 的內存尋址,讀取4個字節,得到該數據的后半部分,再將這兩部分拼接起來,才能取得數據的值。 將一個數據盡量放在一個步長之內,避免跨步長存儲,這稱為內存對齊。在32位編譯模式下,默認以4字節對齊;在64位編譯模式下,默認以8字節對齊。 為了提高存取效率,編譯器會自動進行內存對齊 ~~~ #include <stdio.h> #include <stdlib.h> struct{ int a; char b; int c; }t={ 10, 'C', 20 }; int main(){ printf("length: %d\n", sizeof(t)); printf("&a: %X\n&b: %X\n&c: %X\n", &t.a, &t.b, &t.c); system("pause"); return 0; } ~~~ 在32位編譯模式下的運行結果: ~~~ length: 12 &a: B69030 &b: B69034 &c: B69038 ~~~ 如果不考慮內存對齊,結構體變量 t 所占內存應該為 4+1+4 = 9 個字節。考慮到內存對齊,雖然成員 b 只占用1個字節,但它所在的尋址步長內還剩下 3 個字節的空間,放不下一個 int 型的變量了,所以要把成員 c 放到下一個尋址步長。剩下的這3個字節,作為內存填充浪費掉了。請看下圖: ![](https://box.kancloud.cn/a2c59a3ab589fe3cc21f996425c7c8c9_220x179.png) 編譯器之所以要內存對齊,是為了更加高效的存取成員 c,而代價就是浪費了3個字節的空間。 除了結構體,變量也會進行內存對齊,請看下面的代碼: ~~~ #include <stdio.h> #include <stdlib.h> int m; char c; int n; int main(){ printf("&m: %X\n&c: %X\n&n: %X\n", &m, &c, &n); system("pause"); return 0; } ~~~ 在VS下運行: ~~~ &m: DE3384 &c: DE338C &n: DE3388 ~~~ 可見它們的地址都是4的整數倍,并相互挨著。 經過筆者測試,對于全局變量,GCC在 Debug 和 Release 模式下都會進行內存對齊,而VS只有在 Release 模式下才會進行對齊。而對于局部變量,GCC和VS都不會進行對齊,不管是Debug模式還是Release模式。 # 內存大小端對齊 我們看到上面的十六進制的63,二進制是0110 0011. 那么二進制數據是 ~~~ 0000 0000 0000 0000 0000 0000 0110 0011 ~~~ 因為int是4個字節,1個字節等于8位. 4位一組. 但是內存是16進制表示每8位對應一個16進制 ~~~ 00 00 00 63 ~~~ 內存大小端對齊 ~~~ 63 00 00 00 ~~~ 數組在內存是連續的 后面是0a,十六進制對應十進制是10 正好是下個元素 如果你想在內存地址中看到下個元素,就把那地址+4,注意是16進制表示,結果就是下個元素了 大端和小端是指數據在內存中的存儲模式,它由 CPU 決定: 1. 大端模式(Big-endian)是指將數據的低位(比如 1234 中的 34 就是低位)放在內存的高地址上,而數據的高位(比如 1234 中的 12 就是高位)放在內存的低地址上。這種存儲模式有點兒類似于把數據當作字符串順序處理,地址由小到大增加,而數據從高位往低位存放。 2. 小端模式(Little-endian)是指將數據的低位放在內存的低地址上,而數據的高位放在內存的高地址上。這種存儲模式將地址的高低和數據的大小結合起來,高地址存放數值較大的部分,低地址存放數值較小的部分,這和我們的思維習慣是一致,比較容易理解 ## 為什么有大小端模式之分 計算機中的數據是以字節(Byte)為單位存儲的,每個字節都有不同的地址。現代 CPU 的位數(可以理解為一次能處理的數據的位數)都超過了 8 位(一個字節),PC機、服務器的 CPU 基本都是 64 位的,嵌入式系統或單片機系統仍然在使用 32 位和 16 位的 CPU。 對于一次能處理多個字節的CPU,必然存在著如何安排多個字節的問題,也就是大端和小端模式。以 int 類型的?0x12345678 為例,它占用 4 個字節,如果是小端模式(Little-endian),那么在內存中的分布情況為(假設從地址 0x 4000 開始存放): ![](https://box.kancloud.cn/8b6dc25beb44da9cceb3378c3bf5e540_294x63.png) 如果是大端模式(Big-endian),那么分布情況正好相反: ![](https://box.kancloud.cn/ca66b028e7a0932b1d800ebe3e50814b_291x63.png) 我們的 PC 機上使用的是 X86 結構的 CPU,它是小端模式;51 單片機是大端模式;很多 ARM、DSP 也是小端模式(部分 ARM 處理器還可以由硬件來選擇是大端模式還是小端模式)。 借助共用體,我們可以檢測 CPU 是大端模式還是小端模式,請看代碼: ~~~ #include <stdio.h> int main(){ union{ int n; char ch; } data; data.n = 0x00000001; //也可以直接寫作 data.n = 1; if(data.ch == 1){ printf("Little-endian\n"); }else{ printf("Big-endian\n"); } return 0; } ~~~ 在PC機上的運行結果: Little-endian 共用體的各個成員是共用一段內存的。1 是數據的低位,如果 1 被存儲在 data 的低字節,就是小端模式,這個時候 data.ch 的值也是 1。如果 1 被存儲在 data 的高字節,就是大端模式,這個時候 data.ch 的值就是 0。
                  <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>

                              哎呀哎呀视频在线观看