C语言联合体和枚举

1.联合体

联合体的语法形式和结构体差不多;

联合体的关键字是union,我们来对比一下两者都语法形式:

C语言联合体和枚举_第1张图片

我们可以看见这两者似乎只有关键字上的差异;

那么我们来计算两者都内存关系是否相同;

关于默认对齐数,是根据编译器来确定的,vs的默认对齐数是8;

C语言联合体和枚举_第2张图片

我们发现他们的成员类型都是一样的,但是内存占用大小却不一样,我们前面知道了结构体的内存计算方式,那联合体的内存又是怎样计算的呢?

我们说联合体又叫共用体,联合体的成员共用同一个空间;所以联合体的内存大小至少得存的下那个最大的那个成员的大小;

我们来分析一下上面联合体的内存分布;

C语言联合体和枚举_第3张图片

按照我们上面说的,那么这个联合体的内存大小至少得是1个整型就能存的下整个联合体成员的数据,这2个成员共用同一块空间的化i只需要一块空间就可以存下它的数据;

当然我们也可以通过内存的地址来观察一下:

C语言联合体和枚举_第4张图片

我们可以看到三个地址都是同一个起始位置,这就说明联合体的内存的确是上面那样分布的;

我们前面也特别说了,联合体的内存大小至少是成员里所占内存最大的大小;那就说明还不一定:联合体的内存大小得是最大对齐数的整数倍;(关于对齐数结构体那一章有讲过)

我们来结合实例:

union Un1
{
 char c[5];
//1 8 1
 int i;
//4 8 4
};

我们知道这个联合体的内存大小至少得是5个字节;

如果是结构体成员是数组的话,对齐数就是类型的大小;那么最大对齐数就是4;那么联合体的大小就得是4的整数倍,也就是8;

所以这个联合体的大小实际上是8;

union Un2
{
 short c[7];//14
//2 8 2
 int i;//4
//4 8 4
};

这个联合体的内存大小至少是14个字节,对齐数最大为4,则内存大小至少得是4的整数倍,所以大小是16;

C语言联合体和枚举_第5张图片

基于以上,我们知道联合体的成员是共用一块空间的,那么我们如果改了一个成员的数据是不是所有成员都变了呢?

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

C语言联合体和枚举_第6张图片

确实啊,当我们给成员c赋值后,成员i的值也发生了变化;我们可以来看图:

C语言联合体和枚举_第7张图片

最开始i里面存的是0x11223344,因为是小端机器所以是倒着存的;

我们给从c赋值后,因为2跟成员共用一块空间,且c只占用一个字节,所以就把第一个字节的内容给改成55了;

C语言联合体和枚举_第8张图片

所以在使用联合体时使用其中一个成员就不要使用另外一个成员;

我们再来看一个练习:

例子:判断一个机器是大端存储还是小端存储:

int main()
{
	union m
	{
		char ch;
		int i;
	}k;
	k.i = 1;
	int j = k.ch;
	if (j)
	{
		puts("小端");
	}
	else
	{
		puts("大端");
	}
	return 0;
}

i如果是小端存储的话,那么在内存中存储的就是01 00 00 00;反之则是00 00 00 01;

那么我们取出ch不就是取出i的第一个字节吗?

还有,如果要我们取出一个整型的每个字节呢?

int main()
{
	union s
	{
		int i;
		struct m
		{
			char ch1;
			char ch2;
			char ch3;
			char ch4;
		}j;
	}l;

	l.i = 0x11223344;
	printf("%x %x %x %x\n", l.j.ch1, l.j.ch2, l.j.ch3, l.j.ch4);
	return 0;
}

我们知道结构体中每个成员都是独立的空间,而联合体的成员共用一块空间;按照结构体的内存对齐规则结构体的大小是4个字节,而联合体的成员的最大内存为4字节;对齐数为4,则联合体的大小为4字节;

C语言联合体和枚举_第9张图片

2.枚举

枚举很好理解,枚举的意思就是一一列举;

枚举的语法形式和结构体也一样;

至少关键字不一样,枚举的关键字是enum;

C语言联合体和枚举_第10张图片

枚举可以将可能用到的值一一列举出来,这些枚举类型的成员就叫做枚举常量;

这些枚举常量是有默认值的,我们可以打印出来看一下;

C语言联合体和枚举_第11张图片

如果我们赋初始值的话,第一个成员默认值是0,依次往后递增1;

那如果我们给第一个成员赋值了呢?

C语言联合体和枚举_第12张图片

我们可以看到是从前一个成员的值依次往后地增1的;我们也可以每一个都给一个初始值;

C语言联合体和枚举_第13张图片

但我们一定要注意,当我们在枚举内部给了初始值后,这个值是不能修改的;

C语言联合体和枚举_第14张图片

创建的枚举变量的取值只能取枚举常量;

enum s
{
	MAX=3,
	MIN=6
}m;

int main()
{
	m = MAX;
	printf("%d\n", MAX);
	printf("%d\n", MIN);
	return 0;
}

枚举类型类似#define定义的标识符常量;

C语言联合体和枚举_第15张图片

但是使用枚举定义常量的话会比#define定义常量好一点;

1.枚举定义的枚举常量会有严格的类型检查;

2.枚举可以一次性定义多个常量;

3.枚举是有作用域限制的,出了函数的作用域就失效了;

4,在调试程序的时候有更好的可读性;

5.增加代码的可读性和可维护性

再给枚举变量赋值的时候要给枚举常量的成员,不要给常量数字;

C语言联合体和枚举_第16张图片

在c语言中对语法的检查会不那么严格,但c++会报错,3本身是一个int类型的,m是枚举类型,等号2边的类型不一样;

你可能感兴趣的:(c语言,visual,studio)