struct
1、结构体和数组的差别:能够再结构体里声明数组。结构体变量能够相互赋值。而数组不行。
2、struct与class的差别:class的成员訪问权限默认是private,而struct成员的是public。
3、结构体的定义:
(1)可递归。结构体内部能够使用指针指向自己。比如。链表。
(2)可嵌套。结构体内部能够包括其它的结构体。
4、结构体中的位域。
在存储信息时,不须要占用一个完整的字节,而仅仅须要占几个或一个二进制位。
位域定义与结构定义相仿。其形式为:
struct 位域结构名
{
类型说明符 位域名:位域长度
};
比如:
struct bs { int a:8; int b:2; int c:6; }data;分析:data为bs变量,共占两个字节。
当中位域a占8位,位域b占2位,位域c占6位。
对于位域的定义尚有下面几点说明:
1. 因为位域不同意跨两个字节,因此位域的长度不能大于一个字节的长度。也就是说不能超过8位二进位。如一个字节所剩空间不够存放还有一位域时。应从下一单元起存放该位域。
也能够有意使某位域从下一单元開始。
2. 位域能够无位域名。这时它仅仅用来作填充或调整位置。无名的位域是不能使用的。
比如:
struct bs
{
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*从下一单元開始存放*/
unsigned c:4
}
在这个位域定义中,a占第一字节的4位。后4位填0表示不使用。b从第二字节開始。占用4位。c占用4位。
union
结构体和共用体都是由多个不同类型的数据类型成员组成。可是在任一时刻,共用体中仅仅存放了一个被选中的成员。而结构体
中全部成员都纯在。
对于共用体的不同成员赋值,将会对其它成员重写。原来成员的值就不存在了。
(1)结构体占用内存,可能超过各个成员内存量的和,而共用体占用的内存为各个成员中占用最大者内存。
(2)union和struct在内存中的存放顺序是从地地址開始存放的。
大端存储:数据的高字节存放在低地址中。
小端存储:数据的低字节存放在低地址中。
enum
(1)定义
enum 枚举类型名
{
枚举表
}
比如:
enum ColorEnum1
{
红色, //注意,系统会默认给它赋值为0
蓝色, //系统赋值为1
黑色, //系统赋值为2
粉红色 //系统赋值为3
}
enum ColorEnum2
{
红色=1, //用户自己赋值 所以枚举是一组 符号名称/值 配对
蓝色, // 系统赋值为2
黑色=1, //用户自己赋值1
粉红色 //系统赋值为2
}
所以能够看出。系统会自己给没有赋值的常量赋值。但赋值的方式是依照上一个的值+1来进行操作的
sizeof(struct/union/enum)
一般32位机子上各个数据类型所占的存储空间例如以下:
char:8位
short:16位
int:32位
long:32位
float:32位
double:64位
一、struct,结构体。
请牢记下面3条原则:(在没有#pragma pack宏的情况下)
1、数据成员对齐规则:结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,之后的每一个数据成员存储的起始位置要从该成员大小的整数倍開始(比方int在32位机子上为4字节,所以要从4的整数倍地址開始存储)。
2、结构体作为成员:假设一个结构体里同一时候包括结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址開始存储
(如struct a里有struct b,b里有char,int ,double等元素。那么b应该从8(即double类型的大小)的整数倍開始存储)。
3、结构体的总大小:即sizeof的结果。
在按对齐原则计算出来的大小的基础上。必须还得是其内部最大成员的整数倍.
不足的要补齐(如struct里最大为double,如今计算得到的已经是11,则总大小为16)。
样例:
typedef struct bb { int id; //[0]....[3] 表示4字节 double weight; //[8].....[15] 原则1 float height; //[16]..[19],总长要为8的整数倍,仅对齐之后总长为[0]~[19]为20,补齐[20]...[23] 原则3 }BB; typedef struct aa { int id; //[0]...[3] 原则1 double score; //[8]....[15] short grade; //[16],[17] BB b; //[24]......[47] 原则2(由于BB内部最大成员为double,即8的整数倍開始存储) char name[2]; //[48][49] }AA; int main() { cout<<sizeof(AA)<<" "<<sizeof(BB)<<endl; return 0; }输出结果为56 24
编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。
//n为1、2、4、8、16...
1、n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、假设n大于等于该变量所占用的字节数。那么偏移量必须满足默 认的对齐方式,即该变量所占用字节数的整数倍;第二、假设n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
2、结构体的总大小也有个约束条件,分以下两种情况:假设n大于全部成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。
所以在上面的代码前加一句#pragma pack(1),则代码输出为
bb:(0~3)+(4~11)+(12~15)=16;
aa:(0~1)+(2~5)+(6~13)+(14~15)+(16~31)=32,也就是说,#pragma pack(1)就是没有对齐规则。
再考虑#pragma pack(4),
bb:(0~3)+(4~11)+(12~15)=16;
aa:(0~1)+(4~7)+(8~15)+(16~17)+(20~35)=36
二、union共用体(联合)
在union中,全部的共用体成员共用一个空间。而且同一时间仅仅能储存当中一个成员变量的值。其长度为联合体中元类型最大的变量长度的整数倍。
而且要考虑其它成员变量的对齐。
union foo { char s[10]; int i; }sizeof(foo) 的内存空间的长度为12,而并非数组的长度10。考虑对齐。必需要是4(int的大小)的整数倍。
若把int改为double,则foo的内存空间为16,是double型的两倍。
union mm{ char a;//元长度1 1 int b[5];//元长度4 20 double c;//元长度8 8 int d[3]; 12 };
考虑到8和12的对齐,所以sizeof(mm)=24。
三、enum
enum仅仅是定义了一个常量集合,里面没有元素。把它当做int型存储,所以sizeof的大小为4 byte。
【大小端】
推断大小端的方法:1、利用指针。2、利用union。
#include <stdlib.h> #include <stdio.h> int main() { int x = 0x10000001; char *p = (char *)&x; if (*p) { printf("little "); printf("%d ", *p); } else { printf("large "); } system("pause"); return 0; }
#include "stdio.h" #include<stdlib.h> int main() { union w { int a; //4 bytes char b; //1 byte } c; c.a = 1; if (c.b == 1) printf("It is Little_endian! "); else printf("It is Big_endian! "); system("pause"); return 1; }
以下这段代码输出也耐人寻味。
#include<stdio.h> #include<stdlib.h> union { char i[4]; short x; }s; int main() { s.x = 0; s.i[0] = 256; s.i[1] = 255; s.i[2] = 254; s.i[3] = 253; printf("s.x is %d ", s.x); printf("s.i[0] is %d ", s.i[0]); printf("s.i[1] is %d ", s.i[1]); printf("s.i[2] is %d ", s.i[2]); printf("s.i[3] is %d ", s.i[3]); system("pause"); }