
前置必懂指針大小區(qū)分X86 / X64 X86 (32 位環(huán)境)地址編號 32 位 → 所有指針占 4 字節(jié) X64 (64 位環(huán)境)地址編號 64 位 → 所有指針占 8 字節(jié)int、double、結構體指針、數(shù)組指針不管指向誰指針本身大小全都一樣。補充指針類型決定的是指針加減時的步長不決定指針本身占用字節(jié)。一、結構體 內存對齊核心重點內存對齊 4 條黃金規(guī)則必須背第一個成員放在偏移量為 0 的地址。其余成員要對齊到對齊數(shù)的整數(shù)倍地址。 對齊數(shù) min (編譯器默認對齊數(shù)當前成員所占字節(jié)大小) VS 默認對齊數(shù) 8結構體總大小必須是本結構體最大對齊數(shù)的整數(shù)倍不夠就補空閑填充字節(jié)浪費的空間也叫填充字節(jié) / 補丁。如果結構體里面嵌套另一個結構體嵌套結構體要對齊到「它自己的最大對齊數(shù)」的整數(shù)倍地址最外層結構體總大小是全部成員 (含嵌套結構體) 最大對齊數(shù)的整數(shù)倍。為什么要有內存對齊 CPU 讀取內存是整塊讀取一次讀 4 字節(jié) / 8 字節(jié)。 對齊以后CPU 讀取一個成員只需要讀 1 次內存不對齊就需要讀 2 次內存再拼接數(shù)據(jù)。 用少量空閑內存換取更快的訪問速度。空間換時間。例題講解struct stu1 { char a; //1字節(jié) short b; //2字節(jié) int c; //4字節(jié) };偏移計算 a偏移 0占 1 字節(jié)0 號地址 b對齊數(shù) min (8,2)2地址必須是 2 倍數(shù) → 偏移 2占用 2?3 c對齊數(shù) min (8,4)4地址必須 4 倍數(shù) → 偏移 4占用 4?7 已占用到 7 號地址。最大對齊數(shù) 4。 總大小 8是 4 的倍數(shù)。 sizeof (struct stu1) 8struct stu2 { char a; //1 int c; //4 short b; //2 };a偏移 0占用 0 c對齊數(shù) 4偏移 4占用 4?7 b對齊數(shù) 2偏移 8占用 8?9 目前用到 9 號地址。最大對齊數(shù) 4。 總大小必須是 4 倍數(shù)9 往后最近的 4 倍數(shù)就是 12。 sizeof (struct stu2)12修改默認對齊數(shù)#pragma pack(n)n 只能填 1,2,4,8,16 作用把編譯器默認對齊數(shù)臨時改成 n。 對齊數(shù)公式變?yōu)閷R數(shù) min (n , 成員字節(jié)大小)例#pragma pack(4) struct stu7 { int a; //4 0~3 char b; //1 4 double c; //8min(4,8)4對齊數(shù)4 →偏移88?15 };用到 15總大小 16是最大對齊數(shù) 4 的倍數(shù)。sizeof16。二、位段結構體的進階玩法節(jié)省內存基礎格式struct 名字 { 整型類型 成員名 : 位數(shù); };位數(shù)代表這個成員占用多少個二進制位 (bit)不是字節(jié) 1 字節(jié) 8 bit示例struct Test { unsigned int a : 4; //占用4個比特位 unsigned int : 2; //無名位段占位這2個位不能使用 unsigned int b : 6; //占用6個比特位 };兩個特殊位段 0 位段unsigned int : 0;剩下沒用完的空位直接舍棄強制下一個成員放到一塊全新的存儲單元。無名位段只有冒號和位數(shù)沒有成員名。用來填充空位、對齊這塊空間永遠不能讀寫。位段硬性限制小白必背坑成員類型只能是整型家族int /unsigned int /signed intchar 少數(shù)編譯器支持但不推薦不能寫浮點。單個成員冒號后面的位數(shù)不能超過它本身類型的總比特數(shù)int 最多寫32。不能對位段成員取地址a。地址是按字節(jié)編號位是字節(jié)里面拆分出來的沒有獨立地址。不能做成數(shù)組a[3]:2語法報錯。n 位無符號數(shù)取值范圍0 ~ 2??1有符號?2??1 ~ 2??1?1。賦值超出范圍高位截斷數(shù)據(jù)出錯。補充位段內部 bit 排布大端 / 小端C 標準沒有規(guī)定不同編譯器結果不同??荚囍豢忌厦?5 條規(guī)則不考 bit 內部順序。 優(yōu)點存放大量小范圍標記數(shù)據(jù)大幅節(jié)省內存空間。 缺點不可跨平臺工程開發(fā)慎用。三、枚舉 enum一組有關系的整型常量基礎語法enum 枚舉名 { 元素1, 元素2, 元素3 };默認規(guī)則第一個元素默認值 0往后依次 1。enum Week { Mon, //0 Tue, //1 Wed //2 };手動賦值enum Color { red2, green, //自動1 → 3 blue6, yellow //自動1 →7 };定義變量兩種寫法 寫法 1后面定義推薦int main() { enum Week day; day Mon; }寫法 2定義枚舉類型的時候順便創(chuàng)建變量enum Sex { man, woman } s1,s2;typedef 簡化typedef enum { open, close }Status; int main() { Status st open; }枚舉核心特性枚舉里面的元素都是常量不能修改值。枚舉變量本質就是 int可以做加減運算、比較大小。C 語言語法允許給枚舉變量隨便賦一個整數(shù)但邏輯上不推薦破壞枚舉本意。優(yōu)先用 enum 代替#define定義常量枚舉調試更方便可讀性更強。四、聯(lián)合共用體 union【高頻易混和結構體區(qū)分】核心本質所有成員共用同一塊內存空間同一時刻只能使用其中 1 個成員。一個賦值其余成員數(shù)據(jù)立刻被覆蓋。語法格式union 聯(lián)合名 { 成員1; 成員2; 成員3; };示例union Data { int i; float f; char c; };大小計算規(guī)則 聯(lián)合所占字節(jié)大小 聯(lián)合里面最大成員的字節(jié)大小 ?但是還要對齊聯(lián)合的總大小必須是最大對齊數(shù)的整數(shù)倍。例union Data { char c; // 1字節(jié) int i; // 4字節(jié) };最大成員 4 字節(jié)sizeof (union Data)4。補充例子union Test { char arr[5]; //5字節(jié) int i; //4字節(jié) };最大成員 5 字節(jié)最大對齊數(shù) 4向上取最近 4 的倍數(shù)sizeof8。使用演示union Data d; d.i 10; //現(xiàn)在這塊內存存整數(shù) printf(%d, d.i); d.c A; //覆蓋原來i的數(shù)據(jù) printf(%c, d.c);結構體 VS 聯(lián)合對比表表格類型內存關系內存大小struct 結構體所有成員各自獨立互不干擾同時共存所有成員空間相加 對齊填充字節(jié)union 聯(lián)合所有成員共用一塊內存互斥使用最大成員大小 (還要對齊)五、匿名結構體普通結構體帶名字可以反復創(chuàng)建變量struct Student { int age; }; struct Student s1; struct Student s2;匿名結構體struct 后面不寫結構體名字struct { int age; char name[20]; } stu; //定義的時候必須立刻寫上變量名匿名結構體三條鐵律struct 后面沒有類型名字只能在定義的那一行直接創(chuàng)建變量后面不能再拿這個類型定義新變量。只能一次性使用不能復用。最常見用法嵌套在另一個結構體里面struct Person { int id; struct { int year; int month; } birthday; }; //訪問方式 struct Person p; p.birthday.year 2000;struct /union/ 位段 /enum 匯總對比表格類型內存特點核心考點struct 結構體成員獨立同時共存內存相加 對齊填充內存對齊sizeof 計算union 聯(lián)合成員共用同一塊內存互斥使用共用內存sizeof 取最大成員并對齊位段在整型內部拆分 bit 位節(jié)省空間不能取地址、位數(shù)限制、不能跨平臺enum 枚舉一組整型常量不是變量默認從 0 自增元素是常量刷題坑匯總指針本身大小只看 32/64 位平臺和指針指向什么類型無關指針類型決定1跳多少字節(jié)。內存對齊計算兩步先算每個成員偏移最后結構體總大小要等于最大對齊數(shù)整數(shù)倍。#pragma pack(n)只對當前編譯單元臨時生效n 推薦 1/2/4/8/16。位段不能取地址不能做數(shù)組位數(shù)不能超過基礎類型總 bit。union 所有成員共用內存修改一個其他成員值被覆蓋。匿名結構體定義時必須緊跟變量名后面不能重復使用這個類型。枚舉成員是常量不能賦值修改枚舉變量本質是整型。