摘要:棧上各個變量申請的內存,返回的地址是這段連續內存的最小的地址。為什么用一個位的十六進制來呢因為個字節,一個字節有位,每位有兩個狀態,那么就是,也就是。為什么用,純屬演示方便。結構體里的字節對齊以成員中自身對齊值最大的那個值為標準。
原文:我的個人博客 https://mengkang.net/1046.html鳥哥微博 為什么要字節對齊
初中級 phper 有多久沒給自己充電了呢,安利一波我的直播 PHP 進階之路
需要字節對齊的根本原因在于CPU訪問數據的效率問題。因為CPU每次都是從以4字節(32位CPU)或是8字節(64位CPU)的整數倍的內存地址中讀進數據的。(更深入的原因,誰告知下),如果不對齊的話,很有可能一個4字節int需要分兩次讀取。具體演示看下面的實驗。
數據類型自身的對齊值按各數據類型自身大小進行對齊。變量的內存地址正好位于它長度的整數倍
實驗#includeint main(int argc, char const *argv[]) { char a = 1; // 0x7fff5fbff77f,sizeof(a):1 int b = 1; // 0x7fff5fbff778,sizeof(b):4 int c = 1; // 0x7fff5fbff774,sizeof(c):4 char d = 1; // 0x7fff5fbff773,sizeof(e):1 int e = 1; // 0x7fff5fbff76c,sizeof(f):4 printf("%p,sizeof(a):%lu ",&a,sizeof(a)); printf("%p,sizeof(b):%lu ",&b,sizeof(b)); printf("%p,sizeof(c):%lu ",&c,sizeof(c)); printf("%p,sizeof(d):%lu ",&d,sizeof(d)); printf("%p,sizeof(e):%lu ",&e,sizeof(e)); return 0; }
輔助以圖片說明,該圖左側是上面代碼的內存圖,灰色部分表示該程序未使用的內存。右側是在上面代碼的基礎上在char a后面聲明了一個short f。
從上面的實驗和圖上我們可以找出以下規律:
abcde 五個變量的內存地址從大到下依次分配的;
如果你細看,會發現它們的內存地址并不是緊密挨著的;
而且int 類型的變量的內存地址都是偶數(這也就是為什么鳥哥微博中說的不可能存在奇數的 int 變量的地址了);
再細看,發現 int 變量的地址都是可以被4整除,所以在棧上各變量是按各數據類型自身大小進行對齊的。
新增的short f 地址也并沒有緊挨著a,而是跟自身數據大小對齊,也就是偶數地址開始申請。
棧上各個變量申請的內存,返回的地址是這段連續內存的最小的地址。
反過來想,如果不對齊,比如上例中的 a,b,c 三個變量的內存地址緊挨著,而CPU每次只讀取8個字節,也就是說變量 c 還有最后一個字節沒有讀取進來。訪問數據效率就降低了。
棧上各個變量申請的內存,返回的地址是這段連續內存的最小的地址。這是怎么回事呢?
我們還是通過實驗來驗證下我上面畫的內存圖,假如我有一個int變量,它的值占了滿了4個字節,那么它的四個字節里是怎么存放數據的,我們用十六進制來演示0x12345678。
為什么用一個8位的十六進制來呢?因為int 4個字節,一個字節有8位,每位有0/1兩個狀態,那么就是2^8=256,也就是16^2。所以用了一個8位的16進制數正好可以填滿一個 int 的內存。
為什么用12345678,純屬演示方便。
我先存了變量 b,然后以 char 指針 p 來依次訪問 b 的四個字節的使用情況。
#includeint main(int argc, char const *argv[]) { char a = 1; // 0x7fff5fbff777 int b = 0x12345678; // 0x7fff5fbff770 char c = 1; // 0x7fff5fbff76f printf("%p ",&a); printf("%p ",&b); printf("%p ",&c); char *p = (char *)&b; printf("%x %x %x %x ", p[0],p[1],p[2],p[3]); // 78 56 34 12 printf("%p %p %p %p ", &p[0],&p[1],&p[2],&p[3]); // 0x7fff5fbff770 0x7fff5fbff771 0x7fff5fbff772 0x7fff5fbff773 return 0; }
變量 b 0x12345678的最高位是0x12,最低位是0x78
針對實驗結果我又畫了內存圖,我們可以看到0x12存放在的內存地址要比0x78的大。
這里呢就必須說明下 大小端模式
小端法(Little-Endian)就是低位字節排放在內存的低地址端即該值的起始地址,高位字節排放在內存的高地址端。
大端法(Big-Endian)就是高位字節排放在內存的低地址端即該值的起始地址,低位字節排放在內存的高地址端。
所以,我當前的環境是小端序的形式。
為什么會有大端小端之分?結構體里的字節對齊
這個就得問硬件廠商了,都比較任性,所以歷史就這樣了。
以成員中自身對齊值最大的那個值為標準。
實驗int main(int argc, char const *argv[]) { struct str1{ char a; short b; int c; }; printf("sizeof(f):%lu ",sizeof(struct str1)); struct str2{ char a; int c; short b; }; printf("sizeof(g):%lu ",sizeof(struct str2)); struct str1 a; printf("a.a %p ",&a.a); printf("a.b %p ",&a.b); printf("a.c %p ",&a.c); struct str2 b; printf("b.a %p ",&b.a); printf("b.c %p ",&b.c); printf("b.b %p ",&b.b); return 0; }
結果
sizeof(f):8 sizeof(g):12 a.a 0x7fff5fbff778 a.b 0x7fff5fbff77a a.c 0x7fff5fbff77c b.a 0x7fff5fbff768 b.c 0x7fff5fbff76c b.b 0x7fff5fbff770原理
灰色表填充用來對齊,保證最后結構體大小是最長的成員的大小的整數倍。
實際工作中是否不按字節對齊的情況呢?有的,比如我們的 rpc 框架里面進行數據傳輸的時候,會選擇設置為緊湊型,這樣就可以輕松做到跨平臺,跨語言了。
在網絡程序中采用#pragma pack(1),即變量緊縮,不但可以減少網絡流量,還可以兼容各種系統,不會因為系統對齊方式不同而導致解包錯誤。
實戰舉例 yar_header 中使用 #pragma pack(1) 和 attribute ((packed)) 的意義
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26255.html
目錄 前言 一、 什么是指針? 引例 計算機是怎么對內存單元編號的呢? 內存空間的地址如何得到 想存地址怎么辦? ? 本質目的不是為了存地址 ?二、指針和指針類型 為什么有不同類型的指針 1.指針的解引用 2.指針+-整數 三、野指針 造成野指針的原因 1.未主動初始化指針 ?2.指針越界訪問 3.指針指向的空間釋放 規避野指針 四、指針運算 1.指針+-整數 ?2.指針-指針 ?3.指針的關系運...
摘要:另外棧內存出了作用域就會自動釋放掉,所以不需要手動去回收的。,其中指針變量的聲明有如下三種形式其中第一種是被推薦的寫法。數據類型 C語言中的基本數據類型,對于它分為兩種: 1、signed 有符號的類型,也就是支持正負號的。 2、unsigned 無符號的類型,也就是沒有負號,取值從0開始。 有符號和無符號的數據類型有啥區別呢?其實就是取值范圍不一樣,下面看一張對照表: showImg(ht...
摘要:還在上班很無聊數字華容道暢玩地址開發源碼地址這個叫前言年末了。光隨機生成一個亂序數列是不夠的,還得保證這個數列的逆序數為偶數,嗦嘎。所以,我們直接將交換的次數,記為數列逆序數個數,就達到了想要的效果。 還在上班?很無聊?數字華容道暢玩地址 開發源碼地址 這個叫前言 年末了。哦,不,要過年了。以前只能一路站到公司的我,今早居然是坐著過來的。新的一年,總要學一個新東西來迎接新的未來吧,所以...
摘要:在學習語句的時候,對編程的基礎知識了解的還不是很多,或許沒有做什么太復雜的東西。可以通過一個內置函數來判斷一個條件的結果還是。有朋友需要看完整教程內容,請點擊零基礎學,這里會及時更新,并且有完整的目錄結構,更吸納了朋友們提出的意見和建議。 看官是否記得,在上一部分的時候,有一講專門介紹if語句的:從if開始語句的征程。在學習if語句的時候,對python編程的基礎知識了解的還不是很多,...
摘要:是規則的瀑布流。普通的尺寸會出現錯位的問題索引這個是右邊這個是左邊間距解決辦法,可以通過里的來判斷,這個方法不管你高度怎樣,他都是左右左右開始排列的。 目錄介紹 01.規則瀑布流實現02.不規則瀑布流實現2.1 實現方式2.2 遇到問題03.瀑布流上拉加載04.給瀑布流設置分割線05.自定義Manager崩潰06.如何避免刷新抖動07.為何有時出現跳動08.瀑布流圖片優化09.onBi...
閱讀 2706·2021-11-11 16:54
閱讀 2329·2021-10-09 09:44
閱讀 2548·2019-08-30 15:54
閱讀 1936·2019-08-30 11:24
閱讀 1175·2019-08-29 17:03
閱讀 2107·2019-08-29 16:22
閱讀 2086·2019-08-29 13:11
閱讀 1044·2019-08-29 12:14