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