歡迎來CILMY23的博客喔,本篇為【C語言結構體】用戶自定義類型--結構體,結構體傳參,位段,聯合體和枚舉【圖文詳解】,感謝觀看,支持的可以給個一鍵三連,點贊關注+收藏。
?前言
上一篇(http://t.csdnimg.cn/ruaRw)我們講到C語言中,用戶可以自定義類型,結構體,
?本期將講解結構體的傳參,和位段,聯合體以及枚舉類型。
浮點數的取值范圍:float.h 整型的取值范圍:limits.h
今日語句分享:一個人走慢點也并無害處,因為他的輝煌不在于行走,而在于親身體驗。
目錄
一、結構體傳參
二、位段
三、聯合體
四、枚舉?
一、結構體傳參
結構體傳參也分傳值調用和傳址調用
首先我們來看傳值調用:
struct S
{int b[100];int num;
};void print1(struct S t)
{printf("%d %d %d %d\n", t.b[0], t.b[1], t.b[2], t.num);
}int main()
{struct S s = { {1,2,3},100 };print1(s);
}
結果如下:
?
我們接著來看傳址調用
void print2(struct S* pt)
{printf("%d %d %d %d\n", pt->b[0], pt->b[1], pt->b[2], pt->num);
}int main()
{struct S s = { {1,2,3},100 };print2(&s);
}
結果如下:
?
二、位段
結構體傳參后,我們得講結構體的另外一個能力---位段
2.1什么是位段
位段就是以下這樣的代碼,它是基于結構體實現的,它的出現是為了節省空間,位是二進制位的意思
struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 15;
};
位段的聲明和結構體聲明是類似的,有兩個不同:
1. ? ?位段的成員必須是int、unsigned int 或signed int ,在C99中位段成員的類型也可以選擇其他類型。
2. ? ?位段的成員名后邊有?個冒號和?個數字。?
2.2位段的大小
位段的出現既然是為了節省空間,那上面那段代碼如何解讀呢?
如下所示:
實際上在冒號后面的數字代表的是bit,有幾個數字就有幾個bit位置。?
#include <stdio.h>struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 15;
};struct B
{int _a;int _b;int _c;int _d;
};int main()
{struct A a;struct B b;printf("%d\n", sizeof(a));printf("%d\n", sizeof(b));
}
?結果如下:
?解釋:
2.3位段的內存分配
?看以下這段代碼:
struct S
{char a : 3; char b : 4; char c : 5; char d : 4;
};int main()
{struct S s = { 0 };printf("%d ",sizeof(s));
}
?結果如下:
我們看到大小是3,但是實際上?
1.????位段中內存的空間使用是從左到右還是從右到左使用是不確定的
2.? ? 當前面使用,剩余的空間不足下一個成員存儲,是否繼續使用剩余的空間是不確定的。
那我們接著看下面這段代碼:?
#include <stdio.h>struct S
{char a : 3; char b : 4; char c : 5; char d : 4;
};int main()
{struct S s = { 0 };s.a = 10;s.b = 12;s.c = 3;s.d = 4;printf("%d ",sizeof(s));
}
我們假設在vs上內存分布是從右到左的?
?這里有三個字節
?首先a分配三個bit位,a的數值是10,轉換成二進制是1010,因為只分配3個bit,所以存入010,b的數值是12,轉換成二進制是1100,因為分配4個bit,而之前使用剩余空間足夠,我們繼續存入,c的數值是3,轉換成二進制是011,而分配5個bit,所以存入011,其余用0補齊,d的數值是4,轉換成二進制是100,分配4個bit,由于之前分配給c的bit位置不夠了,我們再拿一個字節來存d,將100存入,然后再用0補齊
那在vs上到底是如何呢?
結果是顯而易見的,正如我們所想的這樣
2.3位段的跨平臺問題?
1. ? ?int在位段中被當成有符號數還是無符號數是不確定的。
2. ? ?位段中最大位的數目不能確定。(16位機器最大16,32位機器最大32,寫成27,在16位機器會出問題。)
3. ? ?位段中的成員在內存中從左向右分配,還是從右向左分配標準尚未定義。
4. ? ?當一個結構包含兩個位段,第二個位段成員比較大,無法容納于第?個位段剩余的位時,是舍棄剩余的位還是利用,這是不確定的。?
2.4 總結
位段總結:
1. ? ?位段的成員可以是int,unsigned int,signed int 或者是char 等類型。
2. ? ?位段的空間上是按照需要以4個字節(int)或者1個字節(char)的方式來開辟的。
3. ? ?位段涉及很多不確定因素,位段是不跨平臺的,注重可移植的程序應該避免使用位段。?
三、聯合體
像結構體一樣,聯合體也是由一個或者多個成員構成,這些成員可以不同的類型。但是編譯器只為最大的成員分配足夠的內存空間。聯合體的特點是所有成員共用同一塊內存空間。所以聯合體也叫:共用體。
3.1聯合體的類型聲明
?union是聯合體的關鍵字,我們對其聲明也跟結構體類似
union U
{char c;int i;
};
3.2聯合體的大小和內存分布
聯合體的大小:
union U
{char c;int i;
};int main()
{union U u = { 0 };printf("%d ", sizeof(union U));
}
結果如下:?
?
那為什么是4呢?這還要從聯合體的成員地址看起
?
我們通過上圖可以看到每個成員的地址的都是一樣的 ,這說明聯合體當中每個成員都是用同一個空間,所以給聯合體其中一個成員賦值,其他成員的值也跟著變化。
?3.3聯合體大小的計算
union Un1
{char c[5];int i;
};union Un2
{char c[7];int i;
};
int main()
{//下?輸出的結果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}
?結果如下:
?聯合體同樣涉及內存對齊
所以un1對齊到8字節,同樣un2也是對齊到8字節
總結:
聯合的大小至少是最大成員的大小。
當最大成員大小不是最大對齊數的整數倍的時候,就要對齊到最大對齊數的整數倍。?
3.4聯合體的練習?
寫一個程序判斷大小端字節序(這個我們之前寫過:http://t.csdnimg.cn/gIUL5)?
int check_sys()
{union U{int i;char c;}u;u.i = 1;return u.c;
}
?那我們可以利用這個聯合體共用一個空間的特性來解決大小端,然后設計一個函數,最后返回c 的值即可。
四、枚舉?
4.1枚舉的類型聲明
枚舉顧名思義就是一一列舉。
把可能的取值一一列舉。
就比如以下這段代碼:?
enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
?以上定義的enum Day是枚舉類型。{}中的內容是枚舉類型的可能取值,也叫枚舉常量。這些可能取值都是有值的,默認從0開始,依次遞增1,當然在聲明枚舉類型的時候也可以賦初值。
enum Day//星期
{Mon = 8,Tues = 10,Wed = 99,Thur = 54,Fri = 55,Sat = 22,Sun = 66
};
4.2枚舉的優點?
我們可以使用? ?#define 定義常量,為什么非要使用枚舉?
枚舉的優點:
1. ? ?增加代碼的可讀性和可維護性
2. ? ?和#define定義的標識符比較枚舉有類型檢查,更加嚴謹。
3. ? ?便于調試,預處理階段會刪除#define 定義的符號
4.? ? 使用方便,?次可以定義多個常量
5. ? ?枚舉常量是遵循作用域規則的,枚舉聲明在函數內,只能在函數內使用?
4.3枚舉類型的使用
?假設我們想描述一個人的性別, 我們就可以用枚舉常量給枚舉類型的變量賦值。那是否可以拿整數給枚舉變量賦值呢?在C語言中是可以的,但是在C++是不行的,C++的類型檢查比較嚴格。
enum Sex
{ MALE,FEMALE,SECREAT
};int main()
{enum Sex S = FEMALE;return 0;
}
感謝各位同伴的支持,本期位段篇就講解到這啦,如果你覺得寫的不錯的話,可以給個一鍵三連,點贊關注+收藏,若有不足,歡迎各位在評論區討論。???