C語言:自定義類型詳解
一、結構體
1.結構體變量的定義及初始化
直接上代碼:
struct Point {
int x;
int y;
}p1; //創(chuàng)建結構體時順便創(chuàng)建變量,分號一定不能掉
struct Point p2; //單獨創(chuàng)建變量
struct Point p3 = { 1,2 }; //創(chuàng)建變量時順便賦值
struct Node {
char str[20];
struct Point p; //結構體嵌套
}n1 = { "abcd",{3,4} };
int main() {
printf("%s\n", n1.str); //結構體訪問時,用.或者->,變量訪問用.,指針訪問用->
printf("%d\n", n1.p.x);
printf("%d\n", n1.p.y);
return 0;
}
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-A5K0M4H1-1632400370757)(C:\Users\10371\AppData\Roaming\Typora\typora-user-images\image-20210923190038919.png)]](http://img.jbzj.com/file_images/article/202109/2021092415582279.png)
struct是創(chuàng)建結構體的關鍵字,Point是結構體的名字,p1為結構體Point的一個變量,x,y稱為結構體Point中的成員變量,變量的創(chuàng)建有兩種形式,第一,可以在創(chuàng)建結構體時一起創(chuàng)建,第二,單獨創(chuàng)建,創(chuàng)建規(guī)則為類型+名稱,對于結構體的賦值,可以在創(chuàng)建變量的時候順便賦值,可以先創(chuàng)建變量再單獨賦值。結構體的訪問有兩種方式,當使用變量進行訪問時,用.(點),再選擇該變量對應的屬性;當使用指針進行訪問時,用->,再選擇對應的屬性即可。
2.結構體內(nèi)存對齊
當我們想去計算結構體占內(nèi)存大小的時候,就需要知道結構圖內(nèi)存對齊這一概念,我們先來看兩個例子:
struct A {
char a;
char b;
int c;
};
struct B {
char a;
int c;
char b;
};
int main(){
printf("%d\n", sizeof(struct A));
printf("%d\n", sizeof(struct B));
return 0;
}
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-u9hpNrap-1632400370761)(C:\Users\10371\AppData\Roaming\Typora\typora-user-images\image-20210923190325486.png)]](http://img.jbzj.com/file_images/article/202109/2021092415582280.png)
結果表明,A和B兩個結構體所占內(nèi)存大小并不相等,但是其內(nèi)部成員變量是一樣的,只是順序不一樣。造成結果不同的原因就是因為內(nèi)存對齊,我們來介紹結構體內(nèi)存對齊的規(guī)則:
1.第一個成員在與結構體變量偏移量為0的地址處。
其他成員變量要對齊到某個數(shù)字(對齊數(shù))的整數(shù)倍的地址處。 對齊數(shù) = 編譯器默認的一個對齊數(shù) 與 該成員大小的較小值。在VS編譯器中,默認對齊數(shù)是8。
結構體總大小為最大對齊數(shù)(每個成員變量都有一個對齊數(shù))的整數(shù)倍。
如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數(shù)的整數(shù)倍處,結構體的整 體大小就是所有最大對齊數(shù)(含嵌套結構體的對齊數(shù))的整數(shù)倍。
3.為什么要內(nèi)存對齊呢?
從上面的結果我們大概就能猜到,為了節(jié)省空間??偟膩碚f,主要原因有兩點:
1.平臺原因:
某些硬件平臺只能在特定的地址處取地址,沒有內(nèi)存對齊,取值時可能會出錯。
2.性能原因:
對于不對齊的情況,在讀取數(shù)據(jù)時可能要讀取兩次,以下圖為例:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jchW9qWz-1632400370763)(C:\Users\10371\AppData\Roaming\Typora\typora-user-images\image-20210923192716935.png)]](http://img.jbzj.com/file_images/article/202109/2021092415582281.png)
在一個32位平臺上,在不對齊的情況下,如果想要讀取int的4個字節(jié),第一次會讀取到char的一個字節(jié),和int的后3個字節(jié)(小端),需要再讀取一次,才能將int的4個字節(jié)完全讀取出來;相比較而言,如果是在內(nèi)存對齊的情況下,只需要讀取一次就可以把int的4個直接讀取出來。
二、位段
結構體還有實現(xiàn)位段的能力,問題來了,什么是位段呢?
1.什么是位段
位段的聲明和結構體是類似的,但有兩點不同:
- 位段的成員必須是 int、unsigned int 或signed int 。
- 位段的成員名后邊有一個冒號和一個數(shù)字。
例如:
struct A
{
int _a:2;
int _b:5;
int _c:3;
int _d:4;
};
A就是一個位段類型,想要知道A的大小,同樣可以用sizeof來求。
2.位段的內(nèi)存分配
拿上面的位段A來說,會先在內(nèi)存中開辟一個4字節(jié)的空間,冒號后面的數(shù)字表示該成員變量所占內(nèi)存的大小,單位為bit,位段中的成員在內(nèi)存中從左向右分配, 當一個結構包含兩個位段,第二個位段成員比較大,無法容納于第一個位段剩余的位時,是 舍棄剩余的位還是利用,這是不確定的??偟膩碚f,跟結構相比,位段可以達到同樣的效果,但是可以很好的節(jié)省空間,但是有跨平臺的問題存在。光說不太好理解,我們來看下圖:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ey3DDX7A-1632400370764)(C:\Users\10371\AppData\Roaming\Typora\typora-user-images\image-20210923200518727.png)]](http://img.jbzj.com/file_images/article/202109/2021092415582282.png)
當然,位段雖然比結構體更節(jié)省內(nèi)存,但其存在跨平臺問題,需要謹慎使用。
三、枚舉
1.枚舉的定義
enum Day//星期
{
Mon, //默認情況下Mon值為0,后面的成員變量的值依次遞增
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
當然也可以在定義的時候賦值,例如:
enum Color//顏色
{
RED=1,
GREEN=2,
BLUE=4
};
2.枚舉的優(yōu)點
我們知道,#define可以定義常量,那為什么要用枚舉呢?
枚舉的優(yōu)點:
1.增加代碼的可讀性和可維護性
2.和#define定義的標識符比較枚舉有類型檢查,更加嚴謹。
3.使用方便,一次可以定義多個常量
既然存在,就有其存在的道理,有些時候#define更方便,有時候枚舉更方便,我們要學會合理使用
四、聯(lián)合(共用體)
1.聯(lián)合類型的定義
union Un //聲明
{
char c;
int i;
};
union Un un; //定義變量
printf("%d\n", sizeof(un)); //計算共用體的大小
2.聯(lián)合的特點
聯(lián)合的成員是共用同一塊內(nèi)存空間的,這樣一個聯(lián)合變量的大小,至少是最大成員的大?。ㄒ驗?聯(lián)合至少得有能力保存最大的那個成員)。
union Un
{
int i;
char c;
};
union Un un;
// 下面輸出的結果是一樣的嗎?
printf("%d\n", &(un.i));
printf("%d\n", &(un.c));
//下面輸出的結果是什么?
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6pp4XA6e-1632400370765)(C:\Users\10371\AppData\Roaming\Typora\typora-user-images\image-20210923202148509.png)]](http://img.jbzj.com/file_images/article/202109/2021092415582283.png)
從結果可以看出,i和c的地址是一樣的,因為他們共用一塊空間,當分別給i、c賦值時,后賦值的c會覆蓋之前i的部分值。
3.聯(lián)合大小的計算
- 聯(lián)合的大小至少是最大成員的大小。
- 當最大成員大小不是最大對齊數(shù)的整數(shù)倍的時候,就要對齊到最大對齊數(shù)的整數(shù)倍。
例如:
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
//下面輸出的結果是什么?
printf("%d\n", sizeof(union Un1)); //8,c占5個字節(jié),比i大,最大對齊數(shù)位4,需要為4的倍數(shù),所以為8
printf("%d\n", sizeof(union Un2)); //16,c占14個字節(jié),最大對齊數(shù)為4,所以為16
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!
相關文章
基于對話框程序中讓對話框捕獲WM_KEYDOWN消息的實現(xiàn)方法
下面我們將通過程序給大家演示基于對話框的應用程序對WM_KEYDOWN消息的捕獲。需要的朋友可以參考下2013-05-05

