自定义类型(结合体、位段、联合体 )

(一)结构体

1.结构体的定义

结构体是一些值的集合,而这些值是结构体的成员变量,当然了结构体内的成员可以是不同类型的变量

2.结构体的声明

先来看一个例子:

struct tag
{
   menmber_list;
}variable-list

在这个结构体中,tag是一个标签,而member-list是结构体的成员变量,那么variable-list是结构体定义的变量·

在这三者之中,tag标签虽然可以省略,但是当你使用结构体定义的变量时会发现不知是哪个,会带来不便,所以不建议省略;

                      member-list是结构体成员,肯定不能省略;

                      variable-list是结构体定义的变量,可以进行省略。

注:特殊的声明

例如:

struct
{
	int a;
	char b;
	float c;
}x;

struct
{
	int a;
	char b;
	float c;
}a[20],*p;

上面的这两个结构体在进行声明的时候省略掉了标签,当进行  p = &x时,编译器会发出警告。把上面两个声明当成完全不同的两个类型是非法的


所以我们在进行结构体声明的时候建议最好不要省略结构体标签

3.结构体变量的定义和初始化
struct Stu
{
	int x;
	int y;
	int c;
}r1;//声明变量的同时也同时定义了变量r1
struct Stu r2; //定义结构体变量r2

struct Stu r3 = {x,y,c};//初始化:定义变量的同时赋初值

在这里我们需要注意的是: 数组可以整体初始化,但是禁止整体赋值,可以单个元素赋初值

                                     那么结构体和数组相似,可以整体赋予初值,但是不允许整体赋值

char arr[10] = {0};//整体赋初值即进行初始化
int arr[20] = {1,2,3,4,6,7,9,0,5,5,6};//整体赋初值即进行初始化
 a = 20;//禁止整体赋值
 a[5] = 3; //可以单个赋值
4.结构体内存对齐问题

先来看一段代码:

struct S1
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%d\n",sizeof(struct S1));
	return 0;
}

按照我们自己的算法结构体大小应该是6,但是结果真的是这样的吗?


可以看到结果和我们想象中的并不一样,于是结构体是存在内存对齐的,我这里的编译器默认的值为8

测试环境VS2008,Win 10

结构体对齐规则:

(1) : 第一个成员在结构体变量偏移量为零的地址处

(2) : 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数=8和该成员大小的较小值,当然了Linux默认的值为4

(3) : 结构体大小为最大对齐数的整数倍

(4) : 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

来看例子(不含嵌套结构体的情况)

struct S3
{
	double d;
	char c;
	int i;
};
int main()
{
	printf("%d\n",sizeof(struct S3));
	return 0;
}

double含有8个字节,从0开始对齐,一直到8,然后char是一个字节,从8开始对齐往后一个字节,那么到int的时候,9不是对齐数,往后偏移3个到12,12再加上int的4个字节,最后对齐的为16,而16正好是8的整数倍,所以结构体大小为16


(含嵌套结构体的情况)

struct S3
{
	double d;
	char c;
	int i;
};

struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
int main()
{
	printf("%d\n",sizeof(struct S4));
	return 0;
}

char类型为1个字节,struct S3为16个字节,1和8中间差了7,所以1+7对齐到8,然后8加上16到24,24再加上double的8个字节到32,32是8的整数倍,所以结构体大小为32


(二)位段

位段 的声明和结构体类似,但是位段的成员必须是int ,unsigned int,signed int

                                               位段的成员名后边有一个冒号和数字

struct A  //A就是一个位段类型
{
	int _a:2;
	int _b:5;
	int _c:10;
	int _d:30;
};

A的大小为8个字节


可以看出位段比结构体要节省空间,但是有跨平台的问题存在

(三)枚举和联合

枚举就是把可能的取值一一列举,枚举不存在内存对齐问题

enum Day
{
	Mon, //枚举常量,默认从零开始,依次递增1,当然了我们自己也可以进行赋初值
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
enum Sex
{
	MALE,
	FEMALE,
	SECRET,
};

以上定义的enum Day,enum Sex都是枚举类型

联合

联合又称为共用体,联合也存在内存对齐问题,联合的成员共用同一块内存空间,所以联合至少得有能力存储最大的成员

union Un
{
	int i;
	char c;
};
union Un un;
int main()
{
	printf("%d\n",&(un.i));
	printf("%d\n",&(un.c));
	return 0;
}

两个输出的结果是一样的


union Un
{
	int i;
	char c;
};
union Un un;
int main()
{
	un.i = 0x11223344;
	un.c = 0x55;
	printf("%x\n",un.i);
	return 0;
}

因为i和c公用同一块内存空间,所以第一个字节里存的是c的内容,剩下的字节里是i的内容


内存对齐问题:

先来看一段代码:

union Un1
{
	char c[5];
	int i;
};
union Un2
{
	short c[7];
	int i;
};
int main()
{
	printf("%d\n",sizeof(union Un1));
	printf("%d\n",sizeof(union Un2));
	return 0;
}

结果为:


计算方法为:(1)联合的大小至少是最大成员的大小

                  (2)当最大成员大小不再是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍

union Un1中 char c[5]占了5个字节,所以int 对齐数为8

union Un2中 short c[7]占了14个字节,所以int对齐数为16

当然了利用联合还可以判断计算机的大小端存储问题

猜你喜欢

转载自blog.csdn.net/ijn842/article/details/79732627
今日推荐