用C語言編程,如何節(jié)省存儲(chǔ)空間?
一、C語言的共用體union
共用體是一種特殊的數(shù)據(jù)類型,允許您在相同的內(nèi)存位置存儲(chǔ)不同的數(shù)據(jù)類型。
什么意思呢,就是在同一塊內(nèi)存存儲(chǔ)可以定義多個(gè)數(shù)據(jù)類型,但是在使用的時(shí)候,只有一個(gè)變量有效。
這里就有一個(gè)問題,變量有大有小呀,對(duì)的,所以這個(gè)時(shí)候共用體的空間為內(nèi)部變量最大占用空間的值。
如此這般,共用體就可以通過共享存儲(chǔ)空間,來避免當(dāng)前沒有被使用的變量所造成的存儲(chǔ)空間的浪費(fèi)。
共用體的成員可以使用任何數(shù)據(jù)類型,但是一個(gè)共用體所占用的存儲(chǔ)空間的字節(jié)總數(shù),必須保證至少足以能夠容納其占用空間字節(jié)數(shù)最大的成員。并且共用體每次只允許訪問一個(gè)成員,也就是一種數(shù)據(jù)類型,確保按照正確的數(shù)據(jù)類型來訪問共用體中的數(shù)據(jù),就是你的責(zé)任了。
先看看union的格式:
union [tag]
{
member definition;
member definition;
...
member definition;
} [variables];
其中:
- union為類型變量;
- tag為共用體的標(biāo)記;
- member definition為變量的定義;
舉個(gè)例子:
union test
{
int i;
float f;
double d;
char str[20];
} data;
通過這個(gè)例子可以看到,這個(gè)結(jié)構(gòu)體的大小是多少呢?可以通過程序來確認(rèn)一下。
OK,這次我們來聊聊結(jié)構(gòu)體。
任務(wù)來了,我想讓你給學(xué)生建立一個(gè)數(shù)據(jù)庫(kù),該怎么來做。
這個(gè)學(xué)生包含的信息如下:
- ID:也就是學(xué)號(hào),唯一區(qū)別碼,用整型表示
- Name:姓名,用字符串表示
- Age:年齡,用整型表示
- Sex:性別,用字符串表示
按照目前學(xué)過的知識(shí)我們的代碼如下,比如先來一個(gè)李雷同學(xué)的吧:
#include
#include
union test
{
int i;
float f;
double d;
char str[20];
};
int main( )
{
union test data;
printf( "data size : %d\n", sizeof(data));
return 0;
}
二、C語言 共用體的訪問
共用體的訪問與結(jié)構(gòu)體類似,也是有2種類型,我們只看看成員訪問運(yùn)算符.。
所以按照通用的賦值方式,來看一下是否按照我們預(yù)定的方式運(yùn)行。
/*beginner/union/union2.c*/
#include
#include
union Data {
int i;
float f;
char str[20];
};
int main()
{
union Data data;
data.i = 123;
data.f = 456.0;
strcpy(data.str, "Hello World");
printf("data.i : %d\n", data.i);
printf("data.f : %f\n", data.f);
printf("data.str : %s\n", data.str);
return 0;
}
從結(jié)果上來看,what are you弄啥嘞,感覺什么跟什么呀,只有最后的字符串是正確的,這也就間接證明了共用體使用相同的存儲(chǔ)空間,其他類型的賦值會(huì)破壞原先的賦值,正常情況下只有最后一次的賦值才會(huì)保證正確結(jié)果。
所以,我們需要在每次賦值后直接查看結(jié)果,是可以保證結(jié)果正確的:
/*beginner/union/union3.c*/
#include
#include
union Data {
int i;
float f;
char str[20];
};
int main()
{
union Data data;
data.i = 123;
printf("data.i : %d\n", data.i);
data.f = 456.0;
printf("data.f : %f\n", data.f);
strcpy(data.str, "Hello World");
printf("data.str : %s\n", data.str);
return 0;
}
再次運(yùn)行,可以看到結(jié)果就按照預(yù)想的進(jìn)行了。
編譯運(yùn)行
#beginner/union/Makefile
ALL : union1 union2 union3
union1: union1.c
gcc -o union1 union1.c
union2: union2.c
gcc -o union2 union2.c
union3: union3.c
gcc -o union3 union3.c
.PHONY : clean
clean:
rm -f union1 union2 union3
輸出結(jié)果
$ ./union2
data.i : 1819043144
data.f : 1143139122437582505939828736.000000
data.str : Hello World
$ ./union3
data.i : 123
data.f : 456.000000
data.str : Hello World
三、除了共用體,還有什么可以節(jié)省存儲(chǔ)?
C語言的結(jié)構(gòu)體位域
前面可以看到,使用unoin共用體可以節(jié)省數(shù)據(jù)的存儲(chǔ)空間。
同樣,在結(jié)構(gòu)體或者共用體中,使用位域也可以達(dá)到這個(gè)效果。
先看看什么時(shí)候可以使用位域,這個(gè)特點(diǎn)大多數(shù)人都不會(huì)用到,用到的大部分人都基本跟底層打交道,比如驅(qū)動(dòng)開發(fā)、單片機(jī)開發(fā)等。
先看一個(gè)最簡(jiǎn)單的例子,比如我們的紅綠燈系統(tǒng),先定義一個(gè)結(jié)構(gòu)體:
typedef struct
{
unsigned int red;
unsigned int green;
unsigned int yellow;
} TrafficLight;
此時(shí)如果看一下TrafficLight結(jié)構(gòu)體的大小,應(yīng)該是12個(gè)字節(jié)
是我們知道對(duì)于這幾種燈而言,只有2種狀態(tài),開和關(guān),也就是1和0,也就是1個(gè)bit其實(shí)就能表達(dá),所以針對(duì)這種情況,有了位域的概念,先看一下位域的聲明:
typedef struct
{
type name : width;
}
- type:整數(shù)類型
- name:為位域的名稱
- width:為位域中位的數(shù)量,其值需要小于等于type指定的類型大小
所以交通燈的結(jié)構(gòu)體使用位域的概念就如下所示:
typedef struct
{
unsigned int red : 1;
unsigned int green : 1;
unsigned int yellow : 1;
} TrafficLight1;
三色紅綠燈加起來一共需要3個(gè)bit,所以一個(gè)無符號(hào)整型就可以容納這些值了,此時(shí)看一下這個(gè)結(jié)構(gòu)體的長(zhǎng)度,應(yīng)該為4。
總結(jié)一下:
當(dāng)結(jié)構(gòu)體或共用體中有無符號(hào)整型或有符號(hào)整型成員時(shí),C語言允許用戶指定這些成員所占用的存儲(chǔ)位數(shù),即位域。通過將數(shù)據(jù)存儲(chǔ)在它們所需的最小數(shù)目的存儲(chǔ)位內(nèi),位域能夠有效地提供存儲(chǔ)空間的利用率,但是,要注意,位域成員必須被聲明為有符號(hào)整型或無符號(hào)整型。
代碼如下:
/*beginner/struct/struct6.c*/
#include
int main()
{
typedef struct
{
unsigned int red;
unsigned int green;
unsigned int yellow;
} TrafficLight;
TrafficLight trafficlight;
printf("The size of TrafficLight %d\n", sizeof(trafficlight));
typedef struct
{
unsigned int red : 1;
unsigned int green : 1;
unsigned int yellow : 1;
} TrafficLight1;
TrafficLight1 trafficlight1;
printf("The size of TrafficLight1 %d\n", sizeof(trafficlight1));
return 0;
}
編譯運(yùn)行
直接輸入make就可以了。
#beginner/struct/Makefile
struct6: struct6.c
gcc -o struct6 struct6.c
運(yùn)行輸出如下:$ ./struct6
The size of TrafficLight 12
The size of TrafficLight1 4
擴(kuò)展
既然位域指定了長(zhǎng)度位,所以就涉及到萬一賦值超過了會(huì)發(fā)生什么情況,可以通過給紅綠燈賦一個(gè)大值看看。
比如復(fù)制一個(gè)2,那么會(huì)得到如下警告:
warning: implicit truncation from ‘int’ to bit-field changes value from 2 to 0 [-Wbitfield-constant-conversion]編譯有警告,不過還是生成了可執(zhí)行文件,運(yùn)行下看看結(jié)果吧。
來源:十月天文版權(quán)歸原作者所有,如有侵權(quán),請(qǐng)聯(lián)系刪除。
▍