结构体
结构体类型的声明
结构是一些值的集合,这些值被称为成员变量。每个结构体的成员变量可以是不同类型的变量。
//结构体的声明 //struct tag //{ // member-list; //}variable-list; // //举例 struct abc { int i; char j; }; struct stu { char name[20]; int age; struct abc a; }stu1; struct stu stu2; int main() { struct stu stu3 = { "zs",10,{97,'a'} }; return 0; }
特殊的匿名声明
struct { char name[20]; int age; }stu4;
去掉标签的结构体是能正常声明的,但是在函数中,这个结构体只能使用一次的,它能声明stu4,无法再拿它去声明其他变量(就像不能 struct stu5 这样声明)在使用中也要注意:
struct { char name[20]; int age; }stu4; struct { char name[20]; int age; }* p; int main() { p = &stu4; }
在监视里面看,输出结果是没有什么问题,但是编译是报了警告的,它指出stu4与p的类型不兼容,编译器把上面两个声明当成了两个不同的类型,说明使用相同的结构体匿名声明不同的变量,实际是不相同的。
结构的自引用
struct stu { char name[20]; int age; struct stu * stu1; };
结构体的自引用是只能通过指针来 ,否则会报错
结构体内存对齐
如果要计算结构体的大小,该怎么计算。
结构体的对齐规则
1、第一个成员在结构体变量偏移量为0的地址处。
2、其他结构体成员变量要对其到对齐数(编译器默认的对齐数与该成员类型大小的较小值)的整数倍的地址处。(vs的默认对齐数为8,部分编译器没有默认对齐数。默认对齐数可以通过预处理命令#pragma更改。)
3、每个结构体大小总为该结构体最大对齐数的整数倍。在嵌套了结构体的情况下,嵌套的结构体对齐到自己最大对齐数的整数倍处,这个结构体的大小就是包括嵌套结构体的最大对齐数的整数倍。
修改默认对齐数
结构体传参
struct S { int data[1000]; int num; }s; //结构体传参 void print1(struct S s) {} //结构体地址传参 void print2(struct S* ps) {} int main() { print1(s);//传结构体 print2(&s); //传地址 return 0; }
地址传参会优于结构体传参,结构体传参会创建一个相同的副本,会造成较大的时间和空间上的系统开销,地址传参是创建指针指向结构体,性能会比结构体传参好。
位段
位段的空间开辟是以4个字节或者1个字节的方式开辟,所以位段的类型只能是int,unsigned int,signed int,char。
位段的声明与结构大致相同,但位段类型有限制,而且位段的成员名后面有冒号和一个数字(给该成员赋给的bit空间,当没有冒号和数字时,则会开辟这个类型相对应的字节空间)。
struct S { char a : 3; char b : 4; char c : 5; char d : 4; };
位段在内存中存放的特点
和结构体相比,位段可以达到相同的效果且可以更节省空间,但是跨平台可以会导致位段错误。
枚举
枚举类型的定义
枚举就是一一列举
枚举常量都是有默认值的,默认从0开始
也可以在定义的时候,给枚举常量赋给初值来改变默认值
枚举的优点
相比#define定义常变量,枚举可以一次定义多个常变量,并且枚举会有类型检查,除此,便于调试,检查,还可以防止命名污染。
枚举的使用
enum Day { Mon, Tues, Wed, Thur, Fri, Sat, Sun }; int main() { enum Day a = Mon; enum Day b = 1; return 0; }
这个枚举使用举例,变量a是正确的使用,b的使用在c可以正常运行,在c++的环境下会报错
联合
联合类型的定义
联合也叫共用体,是一种特殊的自定义类型,这种类型变量包含的一系列成员共用一块空间。
联合的特点
联合共用一块空间,这样一个联合的变量大小,至少是最大成员的大小。
从上面的运行结果来看,字符c与i的第一个字节共用了内存。
联合大小的计算
联合的大小至少是最大成员的大小
当最大成员的大小不是最大对齐数的整数倍时,要与最大对齐数的整数倍对齐