在了解结构体之前我们首先要知道对齐数,因为在我们使用结构体时一定会用到结构体的大小和结构体中相关元素所占的字节,所以必须知道结构体大小的计算规则(对齐规则):
a. 第一个成员在与结构体变量偏移量为0的地址处。
b. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8
c. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
d. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
struct S1
{
char c1;
int i;
char c2;
};
(假设系统对齐数为4)我们来计算一下这个结构体的元素对齐数即结构体大小,首先char类型占一个字节,与4相比1小,所以从c1这个变量的对齐数为1,然后再看int因为interesting为4个字节,与4相同,所以i的对齐数必须为4的倍数,所以从5开始走到8。(2,3)都不是4的倍数所以直接跳过,4刚好是4的倍数所以直接从5开始占4个字节。然后再看c2,char类型占一个字节与第一个相同,所以是一的倍数就可以直接占9,最后再算总的大小,这个结构体类型中,最大的对齐数是4所以结构体的大小必须是4的倍数,但现在结构体中的元素只走到了9,所以需要往后再走3位,走到12,为4的倍数了,则这个结构体的大小为12个字节。
d.可以使用下面这两个代码来改变默认对齐数。
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
1.首先是自定义结构体类型
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
我们针对具体的结构体定义来分析:
(1).
struct S1
{
char c1;
int i;
char c2;
}s;
上面的struct是自定义结构体的特有名词必须使用,s1则为这个结构体类型的名字,而我们想要使用这个结构体时必须定义这个结构体类型的变量来使用,最后面这个s就是这个结构体类型的变量。还可以使用(struct s1 r)这种方法来定义结构体变量,r就是这个结构体变量。
(2.)
typedef struct S3
{
double d;
char c;
int i
}S3;
S s1;
第二种方法便是使用typedef这个方法,typedef的作用大概就是类型定义的作用赋予类型名,具体作用可以去查一下这里只提一下这块的功能,首先定义了这个结构体,,因为使用了typedef来定义所以,最后面的这个s3就拥有了和struct s3一样的功能,就可以直接使用s3来定义结构体变量,所以s1就是这个结构体类型的变量。
2.位段(位段的成员名后边有一个冒号和一个数字)。
使用时应注意这三项规则:
(1.)位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型。
(2.) 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
(3.) 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
a.位段的对齐数的计算和结构体的总大小计算依旧是使用上面的规则(对齐规则)。
b.其中冒号后面的数字:(int)代表字节数。 (char)代表比特位
c.位段我们并不常用到,只有一些特殊需求时需要使用,比如总共给了32个比特位(4个字节),每几个比特位代表不同的信息,而遇到这种需求时,就需要定义这种类型的结构体了,如果学过计算机网络,对这个就可能比较熟悉了,网络层里面的ip数据报的首部格式就是使用这种类型来存储的。
这里只看首部,(数据部分是属于传输层的tcp/udp协议里面的)我们不谈,首部总共有5行每行有32个比特位(4个字节),所以总共占20个字节,即最小20个字节,我们可以看见其中每几个不同的比特位就代表不同信息,这个时候我们就可以使用位段来存储这些信息了。
3.枚举(顾名思义就是把所有的可能一一列举出来),enum为其特有定义类型。
a.比如对星期的取值一共就7天我们可以使用枚举,一一列举。
enum Day//星期
{
Mon,//0
Tues,//1
Wed,//2
Thur,//3
Fri,//4
Sat,//5
Sun//6
};
我们要注意,枚举这个结构体中的值是从0开始逐渐递增的(可以看代码后面的注释),当然我们也可以直接对其进行赋值,注意如对其中的个别赋值,从最后一个赋值的元素开始,后面没有赋值的元素,以这个赋值元素的值为起始继续递增。
enum Day//星期
{
Mon,//0
Tues,//1
Wed=4,
Thur,//5
Fri,//6
Sat=9,
Sun//10
};
4.联合(联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间)(所以联合也叫共用体),union为其特用声明。
//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
a.我们需要注意,这种结构体的大小的计算依然是使用对齐规则进行计算,但因为它是公用一个最大的空间的所以只需要计算它里面元素占用空间最大那个,结构体空间的大小至少是这个最大元素所占用的空间。
b.联合体大小的计算我们要遵循两个规则。
(1)联合的大小至少是最大成员的大小。
(2)当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un1
{
char c[5];
int i;
};
我们来计算一下这个联合体的大小:
首先看这个char类型的数组,总共占了5个字节,因为char类型的最小对齐数为1,所以向后进行到5,然后看int,因为int类型为4个字节,4个字节小与5个字节,并且它可以共用这个内存空间,所以并不往后增长。然后因为这里的最大对齐数是4,所以总的大小必须为4的倍数,因此我们从5往后走到8,所以这个联合体的大小为:8个字节。