C語言深入了解自定義數(shù)據(jù)類型的使用
一、自定義數(shù)據(jù)類型(上)
類型命名關(guān)鍵字 (typedef)
C語言中可以對類型賦予新名字
語法:
typedef Type New TypeName;
注意:typedef 并沒有創(chuàng)建新類型,只是創(chuàng)建了類型別名
深入 typedef 應(yīng)用
- typedef 可在函數(shù)中定義“局部類型名”
- typedef 常用于簡化類型名(如: unsigned long long)
- typedef 定義類型名,能夠以統(tǒng)一的方式創(chuàng)建變量(Type var; )
下面看一段代碼:
#include <stdio.h> typedef unsigned char byte; void func() { typedef byte uint8; uint8 var = 200; byte b = var; // 本質(zhì)為相同類型變量之間的初始化 printf("sizeof(uint8) = %d\n", sizeof(uint8)); printf("var = %d\n", var); printf("b = %d\n", b); } int main() { // uint8 var = 1; // ERROR byte b = 128; func(); printf("sizeof(byte) = %d\n", sizeof(byte)); printf("b = %d\n", b); return 0; }
??????下面為輸出結(jié)果:
????需要注意:本代碼中的 byte 和 uint8 為同一個自定義類型,所以它們之間可以相互賦值。
再來看一段代碼:
#include <stdio.h> typedef float(FArr5)[5]; // 定義數(shù)組類型名 typedef int(IFuncII)(int, int); // 定義函數(shù)類型名 typedef FArr5* PFArr5; typedef IFuncII* PIFuncII; float g_arr[5] = {0.1, 0.2, 0.3}; int add(int a, int b) { return a + b; } int main() { FArr5* pa = &g_arr; // float(*)[5] IFuncII* pf = add; // int(*)(int,int) PFArr5 npa = pa; PIFuncII npf = pf; int i = 0; for(i=0; i<5; i++) { printf("%f\n", (*pa)[i]); printf("%f\n", (*npa)[i]); } printf("%d\n", pf(2, 3)); printf("%d\n", npf(2, 3)); return 0; }
下面為輸出結(jié)果:
這里要特別注意函數(shù)指針的用法,可以通過 typedef 使得函數(shù)指針的定義簡化。
C語言中的結(jié)構(gòu)體( struct )
- struct 是C語言中的自定義類型關(guān)鍵字
- struct能夠定義不同數(shù)據(jù)類型變量的集合類型
語法:
struct TypeName
{
Type1 var1;
Type2var2;
......;
typeN varn;
};
下面看一段代碼:
#include <stdio.h> #include <string.h> struct Student { char name[20]; int id; short major; }; int main() { struct Student s1 = {"Autumn", 908, 1}; struct Student s2 = s1; printf("s1.name = %s\n", s1.name); printf("s1.id = %d\n", s1.id); printf("s1.major = %d\n", s1.major); strcpy(s2.name, "Hu"); s2.id = 909; s2.major = 2; printf("s2.name = %s\n", s2.name); printf("s2.id = %d\n", s2.id); printf("s2.major = %d\n", s2.major); return 0; }
下面為輸出結(jié)果:
小結(jié)
- C語言中通過 typedef 關(guān)鍵字對數(shù)據(jù)類型賦予新名字
- typedef 并不會創(chuàng)建一個全新的數(shù)據(jù)類型
- struct 是C語言中的自定義類型關(guān)鍵字
- struct 用于創(chuàng)建不同數(shù)據(jù)類型變量的集合類型
二、自定義數(shù)據(jù)類型(中)?????
深入 struct 結(jié)構(gòu)體類型
- struct 結(jié)構(gòu)體變量的本質(zhì)是變量的集合
- struct 結(jié)構(gòu)體變量中的成員占用獨立的內(nèi)存
- struct 結(jié)構(gòu)體類型可用 typedef 賦予新類型名
- 可定義struct 結(jié)構(gòu)體類型的指針,并指向?qū)?yīng)類型的變量
- struct 結(jié)構(gòu)體類型可先前置聲明,再具體定義
- 前置類型聲明只能用于指針定義
- 類型完整定義之后才能進行變量定義
- struct 結(jié)構(gòu)體類型可以省略類型名
- 類型名省略時,每次創(chuàng)建變量必須給出完整結(jié)構(gòu)體定義
- struct 結(jié)構(gòu)體類型可以省略類型名(無名結(jié)構(gòu)體類型)
- 類型名省略時,每次創(chuàng)建變量必須給出完整結(jié)構(gòu)體定義
- 無名結(jié)構(gòu)體類型總是互不相同的類型(互不兼容)
先看第1段代碼:
#include <stdio.h> #include <string.h> typedef struct Student Stu; struct Student { char name[20]; int id; short major; }; int main() { Stu s; Stu* ps = &s; strcpy(ps->name, "Autumn"); ps->id = 1; ps->major = 908; (*ps).major = 910; // ==> s.major = 910 printf("s.name = %s\n", s.name); printf("s.id = %d\n", s.id); printf("s.major = %d\n", s.major); return 0; }
下面為輸出結(jié)果:
這里注意結(jié)構(gòu)體變量指針通過 -> 操作符訪問成員變量。
再看第2段代碼:
#include <stdio.h> #include <string.h> struct Test; struct Test* g_pt; // 只要有了類型聲明就可以創(chuàng)建對應(yīng)的指針變量 // 必須先給出類型的完整定義才能創(chuàng)建相應(yīng)類型的變量 struct Test { int a; int b; }; int main() { struct Test t; t.a = 1; t.b = 2; g_pt = &t; printf("g_pt = %p\n", g_pt); printf("g_pt->a = %d\n", g_pt->a); printf("g_pt->b = %d\n", g_pt->b); return 0; }
下面為輸出結(jié)果:
這里注意兩個問題:
1.只要有了類型聲明就可以創(chuàng)建對應(yīng)的指針變量
2.必須先給出類型的完整定義才能創(chuàng)建相應(yīng)類型的變量
再看第3段代碼:
#include <stdio.h> #include <string.h> int main() { struct { int a, b; } v1; struct { int a, b; } v2; struct { int a, b; }*pv; v1.a = 1; v1.b = 2; v2 = v1; pv = &v2; return 0; }
這段代碼編譯會出錯:
這段代碼充分說明無名結(jié)構(gòu)體類型總是互不相同的類型(互不兼容)
位域
- 現(xiàn)代程序設(shè)計中,內(nèi)存使用的最小單位為字節(jié)(約定俗成)
- 在一些特定場合,可將比特位作為最小單位使用內(nèi)存
- 結(jié)構(gòu)體類型能夠指定成員變量占用內(nèi)存的比特位寬度(位域)
深入位域 ???????
- 位域成員必須是整型,默認情況下成員依次排列
- 位域成員占用的位數(shù)不能超過類型寬度(錯誤示例: char c : 9; )
- 當存儲位不足時,自動啟用新存儲單元
- 可以舍棄當前未使用的位,重新啟用存儲單元
下面看一段代碼:
#include <stdio.h> struct BW { unsigned char a : 4; unsigned char b : 2; unsigned char c : 2; }; int main() { struct BW bw = {0}; bw.a = 10; bw.b = 4; // 4 大于 b 能表示的最大值,因此賦值后 b 回轉(zhuǎn)到 0 bw.c = 3; printf("sizeof(struct BW) = %d\n", sizeof(struct BW)); printf("bw.a = %d\n", bw.a); printf("bw.b = %d\n", bw.b); printf("bw.c = %d\n", bw.c); return 0; }
下面為輸出結(jié)果:
這里注意a : 4 ,所以 a 的取值范圍是 0000 ~ 1111 之間,即 0 ~ 15 之間。
再看一段代碼:
#include <stdio.h> #include <string.h> struct Bits1 { int a : 16; short b : 8; char c : 8; float f; // float f : 32; ==> 浮點型成員不能指點位寬度 }; struct Bits2 { unsigned char a : 6; unsigned char b : 6; unsigned char c : 6; // unsigned char d : 9; ==> 指定的位寬度不能大于聲明類型的位寬度 }; struct Bits3 { unsigned char a : 4; unsigned char : 0; // 重啟一個存儲單元表示新的成員 unsigned char b : 4; }; int main() { printf("sizeof(Bits1) = %d\n", sizeof(struct Bits1)); printf("sizeof(Bits2) = %d\n", sizeof(struct Bits2)); printf("sizeof(Bits3) = %d\n", sizeof(struct Bits3)); return 0; }
下面為輸出結(jié)果:
這里注意三點:
1.浮點型成員不能指點位寬度
2.指定的位寬度不能大于聲明類型的位寬度
3.unsigned char : 0 重啟一個存儲單元表示新的成員
小結(jié) ???????
- struct 結(jié)構(gòu)體變量中的成員占用獨立的內(nèi)存
- struct 結(jié)構(gòu)體類型可用 typedef 賦予新類型名
- 結(jié)構(gòu)體類型能夠指定成員變量占用內(nèi)存的比特位寬度
- 位域成員必須是整型,占用的位數(shù)不能超過類型寬度
- 當存儲位不足時,自動啟用新存儲單元
三、自定義數(shù)據(jù)類型(下)?????
C語言中的聯(lián)合體( union )
- union 是C語言中的自定義類型關(guān)鍵字
- union 是 struct 的兄弟關(guān)鍵字,用法上非常相似
語法:
union TypeName
{
Type1 var1;
Type2 var2;
//......
TypeN varn;
};
union 與 struct 的不同
- union 類型所有成員共享同一段內(nèi)存(所有成員起始地址相同)
- union 類型的大小取決于成員的最大類型
- union類型的變量只能以第一個 成員類型的有效值進行初始化
下面看一段代碼:
#include <stdio.h> #include <string.h> union UTest { int a; float f; }; struct STest { int a; float f; }; int main() { union UTest ut = {987654321}; struct STest st = {987654321, 0.1f}; printf("union UTest size = %d\n", sizeof(union UTest)); printf("&ut.a = %p\n", &ut.a); printf("&ut.f = %p\n", &ut.f); printf("struct STest size = %d\n", sizeof(struct STest)); printf("&st.a = %p\n", &st.a); printf("&st.f = %p\n", &st.f); printf("ut.a = %d\n", ut.a); printf("ut.f = %f\n", ut.f); ut.f = 987654321.0f; printf("ut.a = %d\n", ut.a); printf("ut.f = %f\n", ut.f); return 0; }
下面為輸出結(jié)果:
這里注意整型數(shù)據(jù)和浮點類型數(shù)據(jù)在內(nèi)存中的表示方式不一樣,所以在同一段內(nèi)存,同是4個字節(jié),按照整型的方式解釋這4個字節(jié)的數(shù)據(jù)時是一種結(jié)果,按照浮點數(shù)類型解釋這4個字節(jié)時就是另一種結(jié)果。
union 類型的應(yīng)用-判斷系統(tǒng)大小端 ???????
- 小端系統(tǒng):低位數(shù)據(jù)存儲在低地址內(nèi)存中
- 大端系統(tǒng):低位數(shù)據(jù)存儲在高地址內(nèi)存中
例如,對于 unsigned ui = 1;
下面看一段判斷大小端的代碼:
#include <stdio.h> int isLittleEndian() { union { int i; char a[4]; } test = {0}; test.i = 1; return (test.a[0] == 1); } int main() { printf("System Endian: %d\n", isLittleEndian()); return 0; }
下面為輸出結(jié)果:
由代碼可知,1 存在低位,所以我的電腦為小端系統(tǒng)。
C語言中的枚舉類型( enum )
- ???????enum 是C語言中的自定義類型關(guān)鍵字
- enum 能夠定義整型常量的集合類型
???????語法:
enum TypeName
{
IntConst1,
IntConst2,
//......
IntconstN
};
枚舉類型( enum )注意事項
- 第一個枚舉常量的默認值為0
- 后續(xù)常量的值在前一一個常量值的基礎(chǔ)上加1
- 可以任意對枚舉常量指定整型值(只能指定整型值)
例如:
下面看一段代碼,感受一下:
#include <stdio.h> #include <string.h> enum Day { MON = 1, TUE, WED, THU, FRI, SAT, SUN }; enum Season { Spring, Summer = 3, Autumn, Winter = -1 }; enum { CONSTANT = 12345 }; int main() { enum Day d = TUE; enum Season s = Winter; int i = SUN; int j = Autumn; printf("d = %d\n", d); // 2 printf("s = %d\n", s); // -1 printf("i = %d\n", i); // 7 printf("j = %d\n", j); // 4 d = 0; s = -2; printf("d = %d\n", d); printf("s = %d\n", s); printf("sizeof(enum Day) = %d\n", sizeof(enum Day)); printf("sizeof(enum Season) = %d\n", sizeof(enum Season)); printf("CONSTANT = %d\n", CONSTANT); // CONSTANT = 54321; return 0; }
下面為輸出結(jié)果:
這段代碼也說明了 enum 枚舉類型的本質(zhì)就是整型。
小結(jié)
- union 是 struct 的兄弟關(guān)鍵字,用法上非常相似
- union 類型所有成員共享同一段內(nèi)存
- enum能夠定義整型常量的集合類型
- enum 的本質(zhì)是 int 類型,常用于整型常量定義
到此這篇關(guān)于C語言深入了解自定義數(shù)據(jù)類型的使用的文章就介紹到這了,更多相關(guān)C語言 自定義數(shù)據(jù)類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++判斷傳入的UTC時間是否當天的實現(xiàn)方法
在項目中經(jīng)常會顯示一個時間,如果這個時間在今日內(nèi)就顯示為時分秒,否則顯示為年月日,有需要的朋友可以參考一下2014-01-01詳解C++中的內(nèi)存同步模式(memory order)
這篇文章主要介紹了C++中的內(nèi)存同步模式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04C語言SetConsoleTextAttribute函數(shù)使用方法
這篇文章介紹了C語言SetConsoleTextAttribute函數(shù)的使用方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境
這篇文章主要介紹了windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03淺析C/C++ 中return *this和return this的區(qū)別
return *this返回的是當前對象的克隆或者本身,return this返回當前對象的地址,下面通過本文給大家介紹C/C++ 中return *this和return this的區(qū)別,感興趣的朋友一起看看吧2019-10-10Linux中使用VS Code編譯調(diào)試C++項目詳解
最近因為項目的需求,需要在Linux下開發(fā)C++相關(guān)項目,經(jīng)過一番摸索最終實現(xiàn)了,下面這篇文章就給大家簡單總結(jié)了一下如何通過VS Code進行編譯調(diào)試的一些注意事項。有需要的朋友們可以參考借鑒,下面來跟著小編一起看看吧。2016-12-12