国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

2021-09-05_user_defined_data_types(自定義數據類型)

liaosilzu2007 / 2293人閱讀

摘要:如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數含嵌套結構體的對齊數的整數倍。

user_defined_data_types(自定義數據類型)

1,結構體

結構體類型的聲明

結構體自引用

結構體變量的定義和初始化

結構體內存對齊

結構體傳參

結構體實現位段 ( 位段的填充 & 可移植性 )

?
?

2,枚舉

枚舉類型的定義

枚舉的優點

枚舉的使用

?
?

3. 聯合體

聯合類型的定義

聯合的特點

聯合大小的計算

?
?

1,結構體

結構體類型的聲明

    結構體的基礎知識:  結構是一些值的集合,這些值稱為成員變量。結構的每個成員可以是不同類型的變量

?

接下來,讓我們通過程序來進一步加深我們對結構體的認識

程序一:

#include//聲明一個結構體類型//聲明一個學生類型,是 想通過 學生類型 來創建  學生變量(對象)// 描述學生 : 屬性 + 名字 + 性別 + 年齡 + 電話 struct student// struct  結構體 關鍵字  student 結構體 標簽{	char name[10];	char sex[20];	int age;	char telephone[12];// 這四個變量 就是結構體的成員變量}s4,s5,s6; // 創建 結構體 全局變量// 以上所有 就是一個 結構體類型struct student s3; // 創建 結構體 全局變量int main(){	//創建 結構體變量 的方式	struct student s1;	struct student s2;  // 因為 這兩個變量放在 main 函數里,所以是 局部變量	return 0;}

?

特殊的聲明

程序一:

#includestruct          // 缺少一個標簽(名字) 這種結構體類型 稱為 匿名結構體類型     {             // 那么問題來了,沒有名字 該 如何 創建 結構體 變量 ?	char name[10];	char sex[20];	int age;	char telephone[12];}x;// 只有一種方式在結構體末尾分號(;)前面   創建 結構體 全局變量struct          // 缺少一個標簽(名字) 這種結構體類型 稱為 匿名結構體類型     {             	char name[10];	char sex[20];	int age;	char telephone[12];}* px;//  在 匿名結構體 的 全部變量 px 前面加上 * ,該 匿名結構體類型 變成了 匿名結構體指針類型// 即 * px  是一個結構體指針int main(){	px = &x; // 經過 編譯器 編譯, 程序報警,該表達式 是 不合法的	//因為 編譯器, 會把 它們 當做 2 種 不同類型 來處理	// 所以 兩種 不同類型 的數據,是無法進行賦值	return 0;}

?

1,結構體

結構體自引用

程序一:

#includestruct node{	int data;	struct node* next;// 如果 沒有 * 號,也就是數 next 是本身的結構體變量,會導致這個結構體所占內存無限大。    // 這里存地址, 存的是下一個數據的地址:    //結構體自引用 就是 結構體 用指針 找到 與自身同類型的  結構體變量	// 而不是說 結構體自己 包含 結構體自己 的 變量  : struct node next  (error)};int main(){	return 0;}

?
程序二:

#includetypedef struct node  // 這里的 node 是不能省略的, 要不然 下面 沒有這 struct node* next  類型,只能寫成 node* next{                    // 但是 node 是 [把 省略了 node 從而 變成 匿名結構體 的 重命名]。 是后有的,	                 //  也就是說 node 還沒有生成, 就在結構體 調用它,	                 // 這種寫法 是錯誤的	int data;	struct node* next;}node;   // node : typedef 把 結構體 struct node  簡化成 nodeint main(){	node n;	return 0;}

?
?

1,結構體

結構體變量的定義和初始化

程序一:

#includestruct s{	char c;	int a;	double d;	char arr[20];};int main(){	struct s s = { "c", 100, 3.14, "hellworld" };	printf("%c %d %lf %s/n", s.c, s.a, s.d, s.arr);	return 0;}

?
程序二:

#includestruct t{	double weight;	short age;};struct s{	char c;	int a;	double d;	char arr[20];	struct t st;};int main(){	struct s s = { "c", 100, 3.14, "hellworld", {55.6,30} };	printf("%c %d %lf %s %lf %d/n", s.c, s.a, s.d, s.arr, s.st.weight, s.st.age);	return 0;}

?

1,結構體

結構體內存對齊: 用來計算結構體 的 內存大小

結構體的對齊規則:

  1. 第一個成員 在與 結構體變量 偏移量為 0 的 地址處(第一個 結構體成員 存儲的地址,即結構體第一個結構體變量 存儲地址,地址為 0)。
  2. 其他成員 變量 要對齊某個數字(對齊數)的 整數倍 的 地址處

對齊數 = 編譯器默認 的 一個對齊數 與 成員大小的 較小值
vs 中 默認的值為 8; gcc 沒有默認對齊數(成員的大小,就是對齊數)

比如 結構體里 有一個 成員(變量) 為 整形 int 類型 為 4byte
// 而 vs 中 默認值為 8, 4 < 8, 取 4,
// 那么 該成員的 對齊數 為 4

  1. 結構體總大小為 最大 對齊數(每個成員 的 變量 都有 一個對齊數)的整數倍。
  2. 如果嵌套了結構體的情況,嵌套的結構體 對齊 到自己的 最大 對齊數 的整數倍處,
    // 結構體 的 整體大小 就是 所有 最大對齊數(含嵌套結構體的對齊數)的整數倍。
    ?
    程序一:
struct s{	char c1;//  第一個成員 在與 結構體變量 偏移量為 0 的 地址處 (內存所占 1 字節)	int a; //  a 對齊數 是 4 ,因為 其他成員 變量 要對齊 對齊數(4) 的 整數倍 的 地址處(地址4)	// 從 c1(0 地址) 后面開始(從地址 4 開始) 地址 4 處 存放 a,就是說 c1  與 a 之間 隔了 3 個 地址(1,2,3) -> 3 字節	// 此時 a 末尾地址 為 地址8 (因為 a 的存儲 需要 4 byte 空間) 	char c2;//  c2 對齊數 1 ; 其他成員 變量 要對齊 對齊數(1)的 整數倍(倍數為 1) 的 地址處  也就是緊跟 a 后面的 地址8,(char 1 byte)存完之后,末尾地址指向 9;	                                                                                            // 無論是地址幾,都是 對齊數 1 的倍數	// 至此,1+3+4+1 為 9 字節	// 結構體 總大小 為9 字節,但此時地址,不是 成員中 最大 對齊數(4) 的整數倍,	//  12 滿足	// 所以 結構體的大小 最后 為 12 byte};struct s2{	char c1;//  第一個成員 在與 結構體變量 偏移量為 0 的 地址處 (1字節)	char c2;// 對齊數為 1 -> 其他成員 變量 要對齊 對齊數的 整數倍( 倍數為 1 ) 的 地址處(地址1) ,c2 的存儲地址 緊跟在 c1 的后面(2 字節)	int a;// 對齊數 4   -> 其他成員 變量 要對齊 對齊數的 整數倍( 倍數為 4 ) 的 地址處(地址4),(c1 是 0 地址,c2 是1 地址,浪費 2,3地址)	//   即 來到 地址4, 也就是 a 的地址,也就是說 a 與 c2  隔了 2 個地址(浪費了2字節空間),a 的 存儲  也要 占 4 字節	//  1 + 1 + 2 + 4 == 8 字節 	//   成員中 最大對齊數(4) 的整數倍	//  因為 8 == 2*4  > 6 滿足條件	// 所以最后 結構體總大小 為 8};int main(){	struct s s = { 0 };	struct s2 s2 = { 0 };	printf("%d/n", sizeof(s));// 12	printf("%d/n", sizeof(s2));// 8	return 0;}

struct s1附圖 :


12 byte ,滿足成員中 最大 對齊數(4) 的整數倍, 即 結構體大小 為 12 byte
?
?

struct 附圖2:


?
?
程序二:

#includestruct s3{	double d;// 第一個成員 在 與 結構體 偏移量為 0 的地址處(double 8字節,此時地址 指向地址7)	char c;// 對齊數 1 地址8(9字節)	int i;// 對齊數 4   c 后面的 是 地址9,不滿足倍數條件,地址 12 滿足(浪費 9,10,11地址,即 3字節空間),即 i 的地址 是 地址12	// i 占 4 字節,	// 8 + 1 + 3 +4 == 16	//  16 滿足成員中 最大對齊數(8)的整數倍};int main(){	printf("%d/n", sizeof(struct s3));// 16}

附圖:


?
?
程序二:

#includestruct s3{	double d;// 對齊數 8  地址 7	char c;// 對齊數 1  地址 8	int i;// 對齊數 4  地址 12    i 存儲 需要 4byte ,地址 16	//  結構體大小 16 byte 滿足 最大 對齊數(8) 的整數倍	// 故結構體 真正大小 為 16字節};struct s4{	char c1; // 地址0, 對齊數 1	// 嵌套了結構體的情況,嵌套的結構體 對齊 到自己的 最大 對齊數(8) 的整數倍處	struct s3 s3; // 對齊地址 8   然后 結構體 s3 內存大小 為 16 byte	             // 存完16byte之后,地址 24	double d; // 對齊數 8 ,地址24  滿足 對齊數 整數倍 地址 	           // 地址 24 到 地址 32 	           //  32 滿足 最大 對齊數(8)的整數倍	           //  結構體 變量 s4  內存大小 32 字節 };int main(){	printf("%d/n", sizeof(struct s4));// 32}

附圖:


?
?
?

為什么存在內存對齊 : 空間(浪費的) 換取 時間

1. 平臺原因(移植原因):不是所有的硬件平臺都能訪問地址上的任意數據的,

某些硬件平臺智能在某些地址處取某些特定類型的數據。否則拋出硬件異常。

?

2.性能原因:數據結構(尤其是棧)應盡可能地在自然邊界sang對齊,原因在于,為了訪問 未對齊 的內存,

處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問

?
?

那么在 設計結構體的時候,我們既要滿足對齊,又要節省空間,如何做到?

struct s{	char c1;//  第一個成員 在與 結構體變量 偏移量為 0 的 地址處 (內存所占 1 字節)	int a; //  a 對齊數 是 4 ,因為 其他成員 變量 要對齊 對齊數(4) 的 整數倍 的 地址處(地址4)	// 從 c1(0 地址) 后面開始(從地址 4 開始) 地址 4 處 存放 a,就是說 c1  與 a 之間 隔了 3 個 地址(1,2,3) -> 3 字節	// 此時 a 末尾地址 為 地址8 (因為 a 的存儲 需要 4 byte 空間) 	char c2;//  c2 對齊數 1 ; 其他成員 變量 要對齊 對齊數(1)的 整數倍(倍數為 1) 的 地址處  也就是緊跟 a 后面的 地址8,(char 1 byte)存完之后,末尾地址指向 9;	                                                                                            // 無論是地址幾,都是 對齊數 1 的倍數	// 至此,1+3+4+1 為 9 字節	// 結構體 總大小 為9 字節,但此時地址,不是 成員中 最大 對齊數(4) 的整數倍,	//  12 滿足	// 所以 結構體的大小 最后 為 12 byte};struct s2{	char c1;//  第一個成員 在與 結構體變量 偏移量為 0 的 地址處 (1字節)	char c2;// 對齊數為 1 -> 其他成員 變量 要對齊 對齊數的 整數倍( 倍數為 1 ) 的 地址處(地址1) ,c2 的存儲地址 緊跟在 c1 的后面(2 字節)	int a;// 對齊數 4   -> 其他成員 變量 要對齊 對齊數的 整數倍( 倍數為 4 ) 的 地址處(地址4),(c1 是 0 地址,c2 是1 地址,浪費 2,3地址)	//   即 來到 地址4, 也就是 a 的地址,也就是說 a 與 c2  隔了 2 個地址(浪費了2字節空間),a 的 存儲  也要 占 4 字節	//  1 + 1 + 2 + 4 == 8 字節 	//   成員中 最大對齊數(4) 的整數倍	//  因為 8 == 2*4  > 6 滿足條件	// 所以最后 結構體總大小 為 8};

根據 剖析, 發現 結構體成員相同,但是 讓 占用空間小的的成員盡量集中在一起 ,節省很多的空間(也就是不至于浪費很多空間)

?
?

修改默認對齊數

之前我們見過了 #pragma 這個預處理指令,這里讓我們再次使用,可以改變我們的默認對齊數

程序一:

#include#pragma pack(4)   // 設計 默認對齊數 為 4struct s{	char c1;// 1		// 浪費 3 個字節(原本要浪費 7 個 字節,現在只需 3 個字節)	double d; // 8 byte 對齊 為 對齊數 4,【4與8 選擇較小的】 的整數倍 的地址	// 存儲 d  需要 8 個字節 加上前面浪費 3 個 和 c1 1個 字節	// 1+3+8 == 12 字節  	// 這樣寫法,幫我們 避免 了 4 字節 的 空間浪費};#pragma pack() // 取消設置的 默認 對齊數

?
程序二:

 那 我們把 默認對齊數 設置為 1 呢?#include#pragma pack(1)   // 設計 默認對齊數 為 1struct s{	char c1;// 1	// 一個字節的都不會浪費	double d; // 8 byte 對齊 為(對齊數 1,【1與8 選擇較小的】) 的整數倍 的地址	// 存儲 d  需要 8 個字節 	// 1+8 == 9 字節  (9 是 最大 對齊數(1)的 整數倍)	// 這樣寫法,幫我們 避免 了 7 字節 的 空間浪費};#pragma pack() // 取消設置的 默認 對齊數// #pragma pack() 一般設置 默認 對齊數 為 2,4,8, 16   (2的次方數)

?

百度面試題

寫一個宏,計算結構體中某變量 相對于首地址的偏移,并給出說明 (考察 offsetof 宏的實現)

#include#includestruct s{	char c;	int i;	double d;};int main(){	// offsetof 其實是一個宏,用來表示   成員 相對于 結構體 的 偏移量	printf("%d/n", offsetof(struct s, c));// 0	printf("%d/n", offsetof(struct s, i));// 4	printf("%d/n", offsetof(struct s, d));// 8	return 0;      //而且 offsetof 的 參數 傳的是 一個類型,更加說了 offsetof 是一個宏 }

?
?

1,結構體

結構體傳參

#includestruct s{	int a;	char c;	double d;};void init(struct s *tmp){	tmp->a = 100;	tmp->c = "w";	tmp->d = 3.14;}void print(struct s tmp)// 傳值:如果傳遞的結構體對象的時候,結構體過大(空間過大),容易導致 參數壓棧 的 系統 開銷比較大,從而導致系統性能下降。{	printf("%d %c %lf/n", tmp.a, tmp.c, tmp.d);}void print2(const struct s* tmp) // 傳址 : 最好使用這種方法(節省空間),一個地址在操作系統不改變的情況,永遠都是4個字節大小,{       // const 是為了防止 意外改變 結構體變量地址 指向的 值	printf("%d %c %lf/n", tmp->a, tmp->c, tmp->d);}int main() {	struct s s = { 0 };	init(&s);	print(s);	print2(&s);	return 0;}

?
?

1,結構體

結構體 實現 位段 ( 位段的填充 & 可移植性 )

?

位段 的 聲明 和 結構 是 類似的,有 兩個 不同:

1. 位段 的 成員 必須是 int,unsigned int 或 signed int(還可以是 char )

2. 位段 的 成員 后邊 有 一個冒號 和一個數字( 數字 <= 32 [有多少位操作系統決定] )

?

位段 - 位:二進制位

位段的內存分配:

1、位段的成員可以是 int unsigned int,signed int 或者是char( 屬于整形家族 )類型

2、位段的空間上是按照需要 以 4個字節(int)或者1個字節(char)的仿古式來開辟

3、位段涉及很多不確定因素,位段是不跨平臺的,注重 可移植 的 程序 應該 避免使用 位段

?
程序一:

#includestruct a  // 按照以下寫法寫結構體成員, a 已經不是個結構體類型了,而是 一個 位段 類型了// 位段 看見成員 都是 int 類型 ,所以,它 一開始 就創建了 4 byte的 空間{	int a : 2;// 2 這里的意思是: a只需要 2 個比特位(bit)	int b : 5;// 5 這里的意思是: b只需要 5 個比特位(bit)	int c : 10;// 10 這里的意思是:  c只需要 10 個比特位(bit)	int d : 30;// 30 這里的意思是: d只需要 30 個比特位(bit)};// 一共 47 個 bit 位,由已經創建的 4byte 空間來分配空間, 很明顯 空間不夠 大,只能存入 a,b,c,4 byte 空間 還剩 15 bit   d 放不下,怎么辦呢?  在vs 環境中 系統 會舍棄(浪費)剩余的 15 bit 空間 然后, 它再向 空間申請 4 byte(32bit) 空間, 存儲 d 需要 30 bt 空間,這 30 bit 的數據 就存入 這個向系統第二次申請 4 byte 的空間里 至此,數據全部存完,剩余的空間就浪費掉了,也就是說 這 位段 的 內存大小為 8 byteint main(){	struct a a;	printf("%d/n", sizeof(a));// 8 byte	return 0;}

附圖:


&ensp;

位段的意義:

經過上程序,我們發現 原本 a 需要占 4 byte空間,但是 a 只需要 2 bit 的空間, 這樣就形成巨大的空間浪費。

所以 我們通過 位段 這種方式 大大減小了 空間上浪費的問題

(雖然位段也有浪費,但是相比 結構體 浪費的空間要少, b c d 也是同理)

?
?
程序一:

#include// vs 環境struct s // 因為下面 成員類型 為 char 類型,所以它 一開始 就準備 了 1 byte 空間{	char a : 3;//  a 要個 3 bit 位, 由提前準備 1 byte 空間 來分配,還剩 5 bit	// 	char b : 4;// b 要 4 bit 位,由提前準備 1 byte 空間 來分配,還剩 1 bit 空間	char c : 5;// c 要 5 bit 位,由提前準備 1 byte 空間 來分配(剩余 1 bit),不夠大,	// 舍棄(浪費)掉,再向內存申請 1 byte 的空間 來 存儲 c (剩余 3 bit 空間)  	char d : 4;// d 需要 4 bit 位,剩余內存空間(3 bit)不夠,把 3 bit 浪費掉(舍棄)	// 再向內存申請 1 byte 空間,來存儲 d,(剩余 4 bit 空間)	// 至此 數據全部 存儲完畢,剩余的空間 舍棄掉(浪費了)	//  一共向內存 申請了  3 byte 的空間};int main(){	struct s s = { 0 };	s.a = 10;// 1010  因為 a 只有 3 bit 位  所以存入的是 010	s.b = 20;// 10100 因為 b 只有 4 bit 位  所以存入的是 0100	s.c = 3;//  0011  因為 c 只有 5 bit 位  所以存入的是 00011	s.d = 4;//  0100  因為 d 只有 4 bit 位  所以存入的是 0100	return 0;}

附圖:

化作 16 進制 0x 22 03 04 (可以通過調試 -> 內存 -> &s 來觀察 )

?
?

位段 的 跨平臺問題

1. int 位段 被當成 有符號數 還是 無符號數 是不確定的。

2. 位段中 最大位的數目 不能確定。(16 位 機器最大 16,32位機器最大32。寫成 27,在 16 位 機器會出現問題)

3. 位段中 的 成員 在內存中 從左向右分配,還是從右向左 分配標準 尚未定義(由編譯器決定)。

4. 當一個結構包含兩個位段,第二個位段成員比較大,無法容納與 第一個 位段剩余的位時,是舍棄剩余的位還是利用,這是不確定的(由編譯器決定)。

總結: 位段 跟 結構 相比,位段可以達到同樣的效果,且可以很好的節省空間,但是 有 跨平臺的問題存在。

位段 不能 跨平臺 使用

?
?
?
?

2,枚舉: 顧名思義就是 -> 列舉(把可能的取值 一 一 列舉)

舉幾個現實生活的例子

1. 一周 的 星期一 到 星期日 是 有限的 7天,可以 一 一 列舉

2. 性別有:男、女、保密,也可以 一 一 列舉

3.月份有 12 個月,也可以 一 一 列舉

?
?

枚舉類型的定義

程序一:

enum sex// 性別{	// 枚舉的可能取值(枚舉常量)	male,// 0	female,// 1	secret// 2};enum color // 顏色{	// 枚舉的可能取值(枚舉常量)	red,// 0	green,// 1	blue// 2};int main(){	enum day d = mon;//枚舉賦的值,只能是 枚舉的 可能取值	enum sex s = male;//枚舉賦的值,只能是 枚舉的 可能取值	enum color c = blue;//枚舉賦的值,只能是 枚舉的 可能取值  blue 在枚舉的里面 是 2, 那我們 可不可以這樣寫 enum color c = 2  ?  答案是不行,右邊 2int 類型, 左邊的 c 是 enum color 類型	printf("%d %d %d/n", male, female, secret);// 0 1 2	printf("%d %d %d/n", red, green, blue);// 0 1 2  printf("%d/n",sizeof(s)); // 枚舉大小為 4 byte ,為什么呢?                               因為 枚舉常量 的類型是 整形,                              那 s 就是整形變量,所以輸出為 4	return 0;}

?
?
程序二:


            
                     
             
               

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/119303.html

相關文章

  • 行業報告 | 2021.10.06 | 研報目錄更新

    大家好,我們每天全網搜集各行各業的研究報告,了解一個行業從閱讀這個行業的研報開始,今日分享目錄如下: 20211006分享目錄: 2021抖音電商商家經營方法論白皮書-34頁.pdf 2021中國數據智能產業發展研究報告-50頁.pdf 2021公益數字化轉型-56頁.pdf 2021年中國一線城市出行平臺調研報告-77頁.pdf 2021年中國內容機構(MCN)行業發展研究報告-66頁.pd...

    dinfer 評論0 收藏0
  • 《安富萊嵌入式周報》第228期:2021.08.30--2021.09.05

    摘要:論壇下載由于庫是不帶中值濾波器的,需要自己實現,所以花了點時間制作了一個章節。紅色線是波形高斯白噪聲均勻白噪聲。第版教程發布中文顯示章節論壇下載可以直接運行界面效果,也可以使用可以直接編譯運行。上位機已經整合主機,下一版發布 往期周報匯總地址:http://www.armbbs.cn/for...

    劉東 評論0 收藏0
  • 行業報告 | 2021.09.06 | 研報目錄更新

    摘要:參一江湖只作為內容整理方,僅供學習使用。更多相關報告請查看參一江湖星球。 大家好,我們每天全網搜集各行各業的研究報告,了解一個行業從閱讀這個行業的研報開始,今日分享目錄如下: 20210906分享目錄: 2021中國車險科技創新服務研究報告-45頁.pdf 2021年中國家裝行業數字化研...

    junfeng777 評論0 收藏0
  • 行業報告 | 2021.09.28 | 研報目錄更新

    大家好,我們每天全網搜集各行各業的研究報告,了解一個行業從閱讀這個行業的研報開始,今日分享目錄如下: 20210928分享目錄: 休閑娛樂行業主題研究:本地出行,眾彩紛呈-35頁.pdf 休閑服務行業海南折扣觀察第一期:SKU較少的GDF折扣小幅加大,其他公司相對穩定-14頁.pdf 傳媒行業2021年中期策略報告:從流量到留量,抓住年輕人、擁抱視頻化、提升專業化-30頁.pdf 傳媒行業深度...

    LancerComet 評論0 收藏0

發表評論

0條評論

liaosilzu2007

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<