一.联合体:
1.联合体类型的定义:
联合体也是一种特殊的自定义数据类型,这种类型定义的变量也包含一系列成员,特点是这些成员共用同一块空间(所以联合体也叫共用体)。
#include <stdio.h>// 联合体
union MyUnion{
char c;
int i;
};
int main() {
// 计算联合体类型在内存中所占空间的大小
printf("%d\n", sizeof(union MyUnion));
// 使用联合体类型声明变量
union MyUnion u = { 0 };
printf("%p\n", &u);
printf("%p\n", &(u.c));
printf("%p\n", &(u.i));
return 0;
}
2.联合体大小的计算:
- 联合体的大小至少是最大成员的大小
- 当最大成员大小不是所有成员最大位置偏移大小的整数倍时,联合体的整体大小就是所有成员最大位置偏移大小的整数倍
#include <stdio.h>
union MyUnion {
int a;
char arr[5];
};
int main() {
union MyUnion u;
printf("%d\n",sizeof(u));
return 0;
}
二.枚举:
1.将数据进行列举
enum Sex{
//定义的时候是名称首字母大写
MALE,FEMALE
};
enum Color{
//定义的值每个都要大写
RED,
GREEN,
BLUE
};
//定义的enum Sex,enum Color都是枚举类型
//{}中内容是枚举类型的可能取值,也称之为枚举常量
//这些可能取值都是有值的,默认从0开始,依次递增,在定义的时候也可以赋初始值
// 枚举类型
enum Sex{
MALE,
FEMALE = 3
};
enum Color{
RED = 1,
GREEN = 2,
BLUE = 4
};
枚举相较于#define定义常量有自我的优点
- 增加代码的可读性和可维护性
- 和#define定义的标识符比较,枚举有类型检查,更加严谨
- 防止命名污染
- 使用方便,一次可以定义多个常量
2.枚举的使用:
#include <stdio.h>
enum COLOR{
RED,
GREEN,
BLUE=3
};
int main(){
// 声明枚举变量
enum COLOR color = GREEN;
// 使用枚举常量给枚举类型的变量赋值
printf("%d\n",color);
color = 3;
// 也可以将枚举成员视为整型常量,而将枚举变量视为整型变量。因此,可以将一个整型值赋值给枚举变量
printf("%d\n",color);
color = 20;
// gcc编译器对枚举类型进行了扩展,允许给枚举类型的变量赋值任意的整型值
printf("%d\n",color);
printf("please input data to color:");
scanf("%d",&color);
switch(color)
{
case RED:
printf("color is red!\n");
break;
case GREEN:
printf("color is green!\n");
break;
case BLUE:
printf("color is blue!\n");
break;
default:
printf("color not exist!\n");
break;
}
return 0;
}
三.位域(位段)
1.位域类型的声明
位域类型的声明和结构体是类似的,有两个不同
- 带有预定义宽度的变量被称为位域
- 位域必须是int 、unsigned int、 signed int、char和unsigned char类型
- 位域后边有一个冒号和一个数字(所占二进制位的大小)
2.位域分析:
需要一个变量来储存0~7的值,就可以定义一个位数为3的位域
struct stu {
//二进制位数为3
unsigned char age:3;
};
#include <stdio.h>
struct stu {
unsigned char age:3;
};
int main() {
struct stu s;
s.age = 7;
printf("1s.age=%d\n",s.age);
s.age= 8;
printf("2s.age=%d\n",s.age);
s.age= 10;
//二进制1000,进行截断,因此为000
printf("3s.age=%d\n",s.age);
return 0;
}
3.位域说明:
- 如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
- 位域可以是无名位域,这时它只用来填充或调整位置,无名位域不能使用。
- 位域的宽度不能超过它所依附的数据类型的长度。
struct data{
unsigned char a:4;//占了第一个字节的前四位
unsigned char :4; //占了第一个字节的后四位
/* 空域 */
unsigned char b:4;
/* 从下一单元开始存放 */
unsigned char c:4
};
4.位域的使用
位域变量名.位域名
位域指针变量名->位域名
#include <stdio.h>
struct student {
int id:10;
int age:2;
int card:20;
};
int main(){
struct student stu;
printf("sizeof(struct student)=%d\n",sizeof(struct student));
struct student* p_stu=&stu;
stu.id=35;
stu.age=1;
stu.card=12345;
printf("id=%d,age=%d,card=%d\n",stu.id,stu.age,stu.card);
printf("id=%d,age=%d,card=%d\n",p_stu->id,p_stu->age,p_stu->card);
return 0;
}
5.位域的大小计算
- 位域的成员可以是int 、unsigned int、 signed int、char和unsigned char类型
- 位域在空间上是按照需要以4个字节或1个字节的方式来开辟的
- 位域涉及很多不确定因素,位域是不跨平台的,注重可移植的程序应该避免使用位域
总结:
跟结构体相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题。