结构体的概念
結(jié)構(gòu)體的概念
?C語(yǔ)言中有很多的基礎(chǔ)數(shù)據(jù)類(lèi)型,除了這些我們可以通過(guò)一個(gè)結(jié)構(gòu)體來(lái)把一部分基礎(chǔ)數(shù)據(jù)類(lèi)型整合為一個(gè)新的自定義類(lèi)型。
struct 結(jié)構(gòu)體的標(biāo)簽 {
成員1 ;
成員2 ;
.....
}; // 最后用一個(gè)分號(hào)來(lái)表示結(jié)束
?結(jié)構(gòu)體的標(biāo)簽 : 用來(lái)區(qū)分各個(gè)不同類(lèi)型的結(jié)構(gòu)體 (也可以省略)。
?成 員: 指的是該結(jié)構(gòu)體內(nèi)部的數(shù)據(jù),可以是任何數(shù)據(jù)類(lèi)型。也可是結(jié)構(gòu)體
結(jié)構(gòu)體聲明,定義
structnode {
inta;
charc;
doubled;
};
intmain(intargc,charconst*argv[])
{
//定義結(jié)構(gòu)體-->分配內(nèi)存空間
structnodea;
}
注意:
1.只有結(jié)構(gòu)體被定義時(shí)才會(huì)被分配內(nèi)存空間,結(jié)構(gòu)體聲明并不會(huì)分配內(nèi)存空間;
2.定義結(jié)構(gòu)體的步驟:
?a.分配一片內(nèi)存名字叫 a
?b.該內(nèi)存中需要存放一個(gè)結(jié)構(gòu)體
?c.分被存放的是 int a , char c ,double d
結(jié)構(gòu)體初始化
?結(jié)構(gòu)體與普通的變量都是一樣的,都設(shè)計(jì)涉及,初始化,賦值,取值,傳值等等操作。由于結(jié)構(gòu)體中的成員類(lèi)型各有不同因此有兩種初始化得到方法:
?1.普通初始化
??寫(xiě)起來(lái)方便,但是改起來(lái)一點(diǎn)都不方便。
?2.指定成員初始化
??寫(xiě)起來(lái)雖然累一點(diǎn)點(diǎn), 但是如果結(jié)構(gòu)體在后期有更新迭代,不會(huì)有初始化的效果。
//1.普通初始換
structnodec={100,'M',3.1456676};
//2.指定成員初始化
structnoded={
.a=998, // . 稱(chēng)為成員引用符
.c='K',
.d=2345.21345
};
注意:
1.指定成員初始化:
?a.成員的次序或數(shù)量的變化不會(huì)導(dǎo)致初始化有邏輯問(wèn)題;
?b.可以初始化一部分成員;
?c.如果結(jié)構(gòu)體新增成員,該初始化語(yǔ)句依然可用。
結(jié)構(gòu)體成員引用
?由于結(jié)構(gòu)體內(nèi)部包含的成員不止一個(gè),所以說(shuō)需要使用 . 結(jié)構(gòu)體成員的引用符來(lái)訪問(wèn)其中指定的成員。
//結(jié)構(gòu)體變量.結(jié)構(gòu)體成員
printf("a:%d c:%c d:%lf
", d.a,d.c,d.d);
d.a=123; d.c='M'; d.d=3.14;
printf("a:%d c:%c d:%lf
", d.a,d.c,d.d);
結(jié)構(gòu)體數(shù)組
結(jié)構(gòu)體數(shù)組與其他的普通變量的數(shù)組并沒(méi)有差別,只不過(guò)他的數(shù)組內(nèi)容為一個(gè)一個(gè)的結(jié)構(gòu)體。
structnodearr[10];
arr[0].a=200;
arr[0].c='N';
arr[0].d=889.43;
結(jié)構(gòu)體指針
?結(jié)構(gòu)體指針與其他指針沒(méi)有差別,只不過(guò)其指向的是一個(gè)結(jié)構(gòu)體。
structnode*p;
p=&d;
printf("p->a:%d p->c:%c p->d:%lf
", p->a,p->c,p->d);
注意:
1.普通的結(jié)構(gòu)體成員引用使用 .;
2.指針的結(jié)構(gòu)體成員應(yīng)用使用 ->。
結(jié)構(gòu)體聲明的變異
structnode {
inta;
charc;
doubled;
};
//變形 1
structnode {
inta;
charc;
doubled;
}Even, GEC; // 在聲明結(jié)構(gòu)體的時(shí)候順便定義兩個(gè)結(jié)構(gòu)體變量
Even.a=100; Even.c='C'; Even.d=12312.234;
printf("%d %c %lf
",Even.a,Even.c,Even.d);
//變形 2
struct{// 結(jié)構(gòu)體的標(biāo)簽可以省略 ,但是省略的話以后沒(méi)法定義更多的此類(lèi)型結(jié)構(gòu)體
inta;
charc;
doubled;
}Jacy; // 在聲明結(jié)構(gòu)體的時(shí)候順便定義一個(gè)結(jié)構(gòu)體變量
Jacy.a=200;
Jacy.c='A';
Jacy.d=123.2;
printf("%d %c %lf
",Jacy.a,Jacy.c,Jacy.d);
//示例
structCuiHua {
inta;
charc;
doubled;
struct{
char*p;
chararr[32];
}Jacy;//在聲明結(jié)構(gòu)體的時(shí)候順便定義個(gè)結(jié)構(gòu)體變量
}Even,GEC;//在聲明結(jié)構(gòu)體的時(shí)候順便定義兩個(gè)結(jié)構(gòu)體變量
structCuiHuahua={
.a=1024,
.c='B',
.d=123.123,
.Jacy.p="Hello",//p指向的是數(shù)據(jù)段中的Hello的地址
.Jacy.arr="GZ2069"http://數(shù)組arr屬于棧空間,它內(nèi)部存放了"GZ2069"
};
printf("a:%d c:%c d:%lf p:%s arr:%s
",
hua.a,hua.c,hua.d,hua.Jacy.p, hua.Jacy.arr);
hua.Jacy.p=malloc(32);//申請(qǐng)一篇堆空間大小為32字節(jié)讓P指向hello
strncpy(hua.Jacy.p,"hello",32);
hua.Jacy.arr[0]='g'; hua.Jacy.arr[1]='z';
printf("a:%d c:%c d:%lf p:%s arr:%s
",
hua.a,hua.c,hua.d,hua.Jacy.p,hua.Jacy.arr);
// 變形 3 [ 推薦使用 ]
typedefstructCuiHua {
intnum;
char*name;
charclass[32];
}stu_info,*stu_info_p; //使用typedef給結(jié)構(gòu)體取別名
//stu_info等同于structCuiHua
//stu_info_p等同于structCuiHua*
intmain(intargc,charconst*argv[])
{
stu_infoa;//定義一個(gè)普通的結(jié)構(gòu)體變量
a.num=100;
a.name=calloc(1,32);
strncpy(a.name,"張全蛋",32); //注意拷貝之前必須分配空間給a.name。
strncpy(a.class,"GZ206666",32);
printf("Num:%d Name:%s Class:%s
",a.num,a.name,a.class);
stu_info_pc=calloc(1,sizeof(stu_info));//定義一個(gè)結(jié)構(gòu)體指針變量
(*c).num=200;
c->name=calloc(1,32);
strncpy(c->name,"張半蛋",32);
strncpy(c->class,"GZ206667",32);
printf("Num:%d Name:%s Class:%s
",c->num,c->name,c->class);
return0;
}
CPU 字長(zhǎng)
?指CPU一次性從內(nèi)存中獲取的數(shù)據(jù)大小。32位cpu一次性處理4字節(jié)2進(jìn)制數(shù),64位計(jì)算機(jī)一次性處理8字節(jié)2進(jìn)制數(shù)。
地址對(duì)齊
?CPU字長(zhǎng)確定之后就可以確定我們的CPU每一次在讀、寫(xiě)內(nèi)存的時(shí)候都是確定大小 ,假設(shè)是32位系統(tǒng),那么每一次讀、寫(xiě)內(nèi)存時(shí) ,都是按照4字節(jié)進(jìn)行操作。
如果是沒(méi)有對(duì)齊的情況下,需要讀取8字節(jié)則最多需要讀取3次才可以把所有數(shù)據(jù)讀取完整。如果是對(duì)齊的情況下只需要讀取兩次。
?所以,如果地址沒(méi)有對(duì)齊CPU在操作時(shí)需要浪費(fèi)更多的時(shí)間,可以犧牲內(nèi)存來(lái)提高效率。但也可以犧牲效率來(lái)提高內(nèi)存。
普通變量的M值
?變量的地址值,能被M值整除。
char c ; // 大小 1 字節(jié) , M值 1
short s ; // 大小 2 字節(jié) , M值 2
int i ; // 大小 4字節(jié) , M值 4
double d ;// 大小 4字節(jié) , M值 4
printf("a:%p
",&a);
printf("s:%p
",&s);
printf("i:%p
",&i);
printf("d:%p
",&d);
```
注意:
1.如果變量的尺寸小于 4 字節(jié),那么該變量的 m 值等于變量的長(zhǎng)度;
2.如果變量的尺寸大于等于 4 字節(jié),則一律按 4 字節(jié)對(duì)齊;
3.如果變量的 m 值被人為調(diào)整過(guò),則以調(diào)整后的 m 值為準(zhǔn)。
手動(dòng)干預(yù)M值:
char c __attribute__((aligned(4))) ; // 手動(dòng)干預(yù)一般只能往大的設(shè)置不可以設(shè)置更小
注意:
1.__attribute__是GNU特定的語(yǔ)法,屬于C語(yǔ)言的拓展
2.__attribute__寫(xiě)法注意 左右兩邊都是兩個(gè)下劃線右邊有兩組括號(hào) (( ))
3.((aligned(4)))一個(gè)變量M值只能被提高不可以降低
結(jié)構(gòu)體的M值
?結(jié)構(gòu)體的M值取決于結(jié)構(gòu)體中最大成員的M值。結(jié)構(gòu)體的對(duì)長(zhǎng)字節(jié)取決于,結(jié)構(gòu)體中最長(zhǎng)字節(jié)和系統(tǒng)字長(zhǎng)中最短的那個(gè)。
typedefstructCuiHua {
intnum; //4
charc1;//1
char*name; //8
charc2;//1
charc3;//1
double8;//8
charc4;//1
}stu,*p_stu;
intmain(intargc,charconst*argv[])
{
stua;
printf("&a:%p
",&a);
printf("&a.num:%p
",&a.num);
printf("&a.name:%p
",&a.name);
printf("&a.c1:%p
",&a.c1);
printf("&a.c2:%p
",&a.c2);
printf("&a.c3:%p
",&a.c3);
printf("&a.c4:%p
",&a.c4);
printf("&a.d:%p
",&a.d);
printf("sizeof(a):%ld
",sizeof(a)); //輸出40
return0;
}
如上圖所示,在64位系統(tǒng)下結(jié)構(gòu)體a占40個(gè)大小,結(jié)構(gòu)體最大M為8,字體字長(zhǎng)也為8,所以結(jié)構(gòu)體M為8。安裝結(jié)構(gòu)體中變量定義的方式排序,
每個(gè)變量的M值,必須能被變量的起始地址整除,所以得到如上圖所示的存儲(chǔ)方式,每種顏色代表一個(gè)變量。
可移植性
?同樣一份代碼在不同的操作系統(tǒng)下(系統(tǒng)位數(shù)),需要考慮可移植性的問(wèn)題,如數(shù)據(jù)尺寸的變化,存儲(chǔ)位置的變換
//方法1 統(tǒng)一壓實(shí)結(jié)構(gòu)體成員:
structCuiHua {
intnum;//4
charc1;//1
char*name; //8
charc2; //1
charc3; //1
doubled; //8
charc4; //1
}__attribute__((packed)); //把結(jié)構(gòu)體進(jìn)行壓實(shí),不考慮按照順序排列了,能多擠就多擠,當(dāng)然變量的起始地址還是會(huì)被M整除,該結(jié)構(gòu)體大小為24
structCuiHua {
intnum __attribute__((aligned(4)));//4
char c1 __attribute__((aligned(1)));//1
char*name __attribute__((aligned(8)));//4
charc2 __attribute__((aligned(1)));//1
charc3 __attribute__((aligned(1)));//1
doubled __attribute__((aligned(8)));//4
}
總結(jié)
- 上一篇: 4G EPS 中建立 eNB 与 MME
- 下一篇: 如何建立关键词词库