目录
一,联合
是一种数据类型,能在同一块空间中存储不同类型的数据(不是同时存储)。
1,创建联合体
与创建结构体相同
union stu{
int age;
char name;
double gread;
};
//虽然联合内有很多类型,但当声明之后只能存储一个类型
//声明stu 类型的相关变量
union stu s; // stu类型的联合变量
union stu arr[2]; //内含两个联合变量的数组
union stu *p; //指向stu类型联合的指针
声明s时,编译器分配空间,分配的空间能存储声明中占用最大的字节类型(例子中为double类型)
2,初始化联合体
联合体只能存储一个值
方法一:把一个联合体初始化为另一个同类型的联合体
方法二:初始化联合的第一个元素
方法三:使用指定初始化器
union stu s1;
union stu s2;
s2.age = 18;
s1 = s2; //用同类型联合初始化
union stu s3 = { 20 }; //初始化第一个元素age
union stu s4 = { .age = 18 }; //指定初始化器
3,使用联合体
3.1普通用法
union stu s ;
s.age = 18 ; //把18存储在age,占用4字节
s.name = 'r' ; //清楚上述 18 ,存储r ,占用1个字节
s.gread = 59.5 ; //清楚上述 r ,存储59.5,占用8个字节
点(.)运算符表示正在使用哪种数据类型,在联合体中,一次存储一个值。即使有足够的空间,也不能同时存储两个类型的值。
3.2指针用法
当然也可以通过指针使用联合:
union stu
{
int age;
char name;
double gread;
}s;
union stu* p = &s;
s.age = 18;
int x = p->age; //相当于 s.age
注意:使用联合体时要注意不要用错,比如:
s.age = 20 ; //这里存储的是age的内容
int x =s.gread / 100 ; //但是这里使用的是 gread的内容,这样做是错误的
4,匿名联合
4.1匿名结构体
匿名结构体就是没有名称的结构体内容
struct
{
char name[20];
int age;
char id[20];
};
4.2匿名联合体
和匿名结构体类似,是一个没有名称的联合体
union
{
int age;
char id;
double gread;
};
二,枚举
这一通过枚举类型声明符号名称来表示整型常量,使用关键字enum。
enum常量是int类型,所以只要能使用int类型的地方就可以使用枚举类型
1.定义
enum color //声明枚举类型
{
red, // 0 默认值
green, // 1
blue // 2
};
//从上到下 默认递增 1
red,green,blue这些被称为枚举符,默认为int类型的值,所以枚举常量可以在switch语句中作为标签。
2.赋值
enum color //声明枚举类型
{
red , //默认值 0
green , // 1
blue = 200 ,
yellow, //从上到下递增1 所以yellow是201
orange //orange 是202
};
如果只给一个枚举常量赋值,没有对后面的枚举常量赋值,那么后面的枚举常量就是被赋予的值 的后续值;第一个如果没有被赋值仍然是默认值0。
3.枚举的优点
- 增加代码的可读性和可维护性
- 和#define定义的标识符比较,枚举有类型检查(int类型),更加严谨
- 防止了命名污染(封装)
- 便于调试
- 使用方便,一次性可以定义多个常量
三,位段
1.位段的定义
位段类似于结构体,但是两点不同:
- 位段的成员必须是 int ,unsigned int ,signed int ,char;
- 位段的成员名后面有一个冒号和一个数字
struct A
{
int a : 2 ; //a成员占 2 个 bit位
int b : 3 ;
int : 4 ; //没有指定名称的位段
}s;
冒号后面为指定的成员所占内存长度 ,需要注意的是这个长度不能超过该类型所能表示的最大长度,这个长度表示二进制长度。
比如32位机中,int占用32位,所以int 类型被指定的长度不能超过32 ;
对上述位段进行赋值操作观察其打印的值:
打印值时我们发现 a,b 正数的15变成了,输出的时候变成了-1,而c没有变这是为什么?
2.位段的内存分配
VS编译器中是从右向左,剩余内存不够,浪费掉
1:位段的空间是按照需要以四个字节(int)或者 一个字节(char)的方式开辟的
2:位段涉及很多不确定因素,位段是不可以跨平台的,注重移植的程序应该避免使用位段
3:上述代码中没有指定名称的位段是无法进行访问的,但计算位段大小时仍会计算在内。
3.位段的跨平台问题
- int位段被当成有符号数还是无符号数是不确定的
- 位段中最大位的数,不能确定,如:16位机器中最大16位,32位机器中最大32,写成26在16位机器中是会报错的
- 位段中的成员在内存中从左向右分配还是从右向左分配标准是没有定义的
- 当一个结构包含两个位段,第二个位段成员比较大,无法容纳与第一个位段所剩余的位时,是舍弃剩余的位,还是利用的,不确定
4.位段注意事项
- 位段所占的位数,不能超过该类型的最大位数
- 在位段里,不给位段起名字将不能访问该位段,但是计算内存大小时任然会将该位段算在内(sizeof())计算。
- 不可以对位段进行取地址操作
- 如果位段被赋值的二进制位数大于位段自身的大小时,在使用时会发生截断问题,截断后的最高位表示符号位。当位段类型定义是无符号类型时,将不会有变成负数这个问题
- 使用位段时应该注意程序是否注重可移植性