自定義類型與內存對齊

一、結構體

1、聲明:

方法一:

struct 類型名

{

成員變量;

}(變量名);

struct 類型名 變量名 ;//定義結構體變量

struct 類型名 變量名 = {數據,...};//定義結構體變量同時初始化


方法二:

typedef struct 類型名

{

成員變量;

} (自定義類型名)
自定義類型名  變量名 ;//定義結構體變量

注:結構體中的成員變量不可在結構體中進行初始化。      

       結構變量用'.'進行引用成員。     

      結構體指針變量用->引用成員列:


二、內存對齊

linux默認對齊數爲 4 , vs默認對齊數爲 8

#pragma pack (n);//修改默認對齊數爲n (0<n<8(4),n=0 或 n>默認值,n取默認值)

內存對齊計算方法:

1、類型所佔字節 與 默認對齊數比較 取小的作爲對齊數

2、此變量所佔總字節 + 之前所佔字節 總字節轉變爲對齊數的倍數(最接近)

3、最終總大小轉變爲 所取最大對齊數的倍數(最接近)

列:

typedef struct Test2{    //默認對齊數 8
	 char c;                 //char  1 < 8 對齊數1 佔1字節                        偏移 0
	 int num;                //int   4 < 8 以4對齊 佔4+1=5字節   5--4的倍數-->8   偏移 3
	 struct Test2 *Next;//鏈表  指針  4 < 8 以4對齊 佔4+8=12字節 12--4的倍數-->12  偏移 0
	}p,*node;  //12--所取最大對齊數倍數-->12  偏移 0  結構體大小 12
	//注:此處p,和*node 爲類型名,p 結構體類型,node 結構體指針類型 

代碼示例:

void structb(void){
	typedef struct Test2;//結構體聲明
    typedef struct Test2{    //默認對齊數 8
	 char c;                 //char  1 < 8 對齊數1 佔1字節                        偏移 0
	 int num;                //int   4 < 8 以4對齊 佔4+1=5字節   5--4的倍數-->8   偏移 3
	 struct Test2 *Next;//鏈表 指針  4 < 8 以4對齊 佔4+8=12字節 12--4的倍數-->12  偏移 0
	}p,*node;  //12--所取最大對齊數倍數-->12  偏移 0  結構體大小 12
	//注:此處p,和*node 爲類型名,p 結構體類型,node 結構體指針類型 
	p p1;//定義結構體變量p1
	p * pnew;//定義結構體指針變量 pnew
	node head;//定義結構體指針變量 head
	p1.c='1';
	pnew=(p*)malloc(sizeof(p));//開闢一個結構體空間的大小
	pnew->num=12;
	//加{}好後所有設置僅在括號內有效
	{
	#pragma pack (4)//設置默認對齊數爲4
	//聲明瞭一個結構體,結構體類型名 Test
     //將結構體Test2作爲成員變量,結構體必須在其之前定義
	struct Test{       //默認對齊數 4
	 int a;            //int    4 = 4 第一個不對齊 對齊數爲4 佔4字節             偏移 0
	 char ch;          //char   1 < 4 以1對齊 佔4+1=5個字節      5--1的倍數-->5  偏移 0
	 char arr[5];      //char   1 < 4 以1對齊 佔5*1+5=10個字節  10--1的倍數-->10 偏移 0
	 double num;       //double 8 > 4 以4對齊 佔8+10=18個字節   18--4的倍數-->20 偏移 2
	 //tp爲Test2的結構體類型,取其中取得的最大對齊數與默認之比較
	 struct Test2 tp;  //tp     4 = 4 以4對齊 佔12+20=32個字節  32--4的倍數-->32 偏移 0
	 int * p ;         //int    4 = 4 以4對齊 佔4+32=36個字節   36--4的倍數-->36 偏移 0
	}ta,test[10]; //36--所取最大對齊數倍數-->36  偏移 0  結構體大小 36 
	//注:此處ta,與test爲變量名
	struct Test tb;//定義結構體變量tb

	printf("Test:%d\n",sizeof(ta));
	}

	printf("%c\n",p1.c);
	printf("%d\n",pnew->num);
	printf("%p\n",&p1.c);
	printf("%p\n",&p1.num);
	printf("%p\n",&p1.Next);
	printf("Test2:%d\n",sizeof(p1));
}


三、位段
1、位段與結構體類似,只是成員變量大小爲比特位
2、連續相同類型所佔字節數和 < 該類型所佔字節大小 則共同分配該類型空間
3、若類型不同,或連續相同類型所佔字節數和 > 該類型所佔字節大小,則分別開闢一塊內存空間
4、內存對齊問題與結構體類似
5、位段共用一個地址時不會發生數據覆蓋問題
6、位段的聲明與定義類似

代碼講解:
void struct_bit(void)
{
	struct Bit{   //聲明一個位段
	int  b1 : 2;//b1佔2個bit位int類型   int  4 < 8  對齊數 4  所佔字節4
	char b2 : 3;//b2佔3個bit位char類型  連續同類型 b2+b3<8 共佔1個字節
	char b3 : 4;//b2佔4個bit位char類型  char 1 < 8  對齊數 1  所佔字節  1+4=5  --1的倍數-->5  偏移 0
	char b4 : 2;//b4佔2個bit位char類型 
	char    : 4;//  佔4個bit位char類型  連續同類型 b4+4+bit5<8 共佔1個字節
	char b5 : 1;//b5佔1個bit位char類型  char 1 < 8  對齊數 1  所佔字節  5+1=6  --1的倍數-->6  偏移 0
	int  b6 ;   //b6佔32個bit位int類型  int  4 < 8  對齊數 4  所佔字節  6+4=10 --4的倍數-->12 偏移 2
	}bit; //定義一個位段變量             12--最大對齊數倍數-->12  偏移 0  總大小爲 12
	printf("%d\n",sizeof(bit));

	bit.b1=5;  // 5-->0101 僅存低2bit位   01->1
	bit.b2=10; //10-->1010 僅存低3bit位  010->2
	bit.b3=3;  // 3-->11   僅存低4bit位 0011->3
	bit.b4=2;  // 2-->10   僅存低2bit位   10->2
	//b2,b3共用一個字符的地址,不發生數據覆蓋
	printf("%d\n",bit.b1);//%d 提升取32bit位輸出 01前補符號位0  變成1  
	printf("%d\n",bit.b2);//%d 提升取32bit位輸出 010前補符號位0 變成2
	printf("%d\n",bit.b3);//%d 提升取32bit位輸出 010前補符號位0 變成3
	printf("%d\n",bit.b4);//%d 提升取32bit位輸出 10前補符號位1 變成-2
	printf("%u\n",bit.b4);//%d 提升取32bit位輸出 10前補符號位1 變成無符號類型4294967294
}

四、聯合體

1、聯合體中的成員共用一塊內存地址,存在數據覆蓋問題
2、聯合體的大小取其中最大那個

3、聯合體的聲明與定義與結構體類似

實例講解:

void combo(void)//聯合體(共用體)
{
 union in //聲明一個聯合體

{  
  char c;
  int  n;
 }u; //定義一個聯合體變量u


 u.c='1';//'1'-->49
 u.n=48; //'0'-->48  將之前的數據覆蓋
 printf("%c\n",u.c);
 printf("%d\n",u.n);
// 字節   高        低
  u.n=0x11223344;//小端存儲 低字節存低地址
 u.c=0x55;      //低地址中的字節被修改
 printf("%x\n",u.n);//11223355
}

五、枚舉

1、枚舉中的成員是常量值
2、枚舉中的成員若未初始化,則取默認值,第一個成員默認值爲0,往後依次加1
3、若某一成員進行了初始化,則從該成員起,往後依次加1
4、枚舉的類型爲整型類型
5、枚舉類型變量初始化時,最好使用其中的成員進行初始化
6、枚舉中的成員用 , 分開
7、枚舉的定義與聲明與結構體類似


實例講解:

void enumj(void)//枚舉
{
 enum Color{    //聲明一個結構體類型 類型名Color
 red,     //默認0
 blue,    //1
 green=6, //6
 black,   //7
 }color;  //定義一個枚舉變量

 enum Color color1=red;//定義一個枚舉變量 初始化 red
 enum Color color2=black;
 color1=green;

 printf("%d\n",color1);
 printf("%d\n",color2);
 scanf("%d",&color);

 switch(color)
 {
 case red:
  printf("紅色\n");
  break;
 case blue:
  printf("藍色\n");
  break;
 default :
  break;
 }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章