枚举
enum提供了创建常量的方式,可以替代const。使用#define和const可以创建符号常量,使用enum不仅可以创建符号常量,还能定义新的数据类型。
枚举类型的声明和定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| enum wT{ Monday, Tuseday, Wednesday, Thursday, Firday, Saturday, Sunday };
wT weekday;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream> using namespace std; int main() { enum wT{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; wT weekday; weekday = Monday; weekday = Tuesday; cout << weekday << endl;
int a = Wednesday; cout << a << endl;
return 0; }
|
使用细节:
- 枚举值不能做左值;
- 非枚举变量不可以赋值给枚举变量;
- 枚举变量可以赋值给非枚举变量;
enum只是定义了一个常量集合,里面没有元素,在内存中是当作int存储的。sizeof的值为4.
结构体和联合体
结构体与数组有两点不同:结构体可以在一个结构中声明不同的数据类型;相同的结构体可以相互赋值,但数组不行。
联合体(共用体)都是由不同的数据类型成员组成,但联合体同一时间只存放一个被选中的成员。如果对联合体的不同成员赋值,将会对其他成员重写。共用体的用途是当数据项使用多种格式单不会同时使用时,可以节省空间。
结构体和联合体的在内存中是小端存储的,从低地址开始存放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| struct Student { char name[6]; int age; Score s; };
union Score { double sc; char level; };
struct person { struct person* per; };
struct person{ char name[20]; char sex; }boy1 = {"xiaoming", 'M'};
|
结构体中的位字段
有些信息在存储时,并不需要占用一个完整的字节,只需要占用几个或一个二进制位。位了节省存储空间,C预言提供了一种数据结构,称为“位域”或“位段”。
C/C++允许指定占用特定位数的结构成员。字段的类型应该为整形或枚举,接下来是冒号,冒号后面指定使用的位数,且可以使用没有名称的字段来提供间距。每个成员都被称为位字段。赋值时不能超过位域的允许范围,如果超过,仅将等号右侧值的低位赋给位域。
1 2 3 4 5 6 7 8 9
| struct reg{ unsigned int SN:4; unsigned int :4; bool good:4; };
reg r = {14, true};
|
存储结构与结构体数据对齐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <string.h> #include <iostream> using namespace std;
int main() { union Score { double ds; char level; };
struct Student { char name[6]; int age; Score s; };
cout << sizeof(Score) << endl; Student s1; strcpy_s(s1.name, "lili"); s1.age = 16;
s1.s.ds = 95.5; s1.s.level = 'A';
cout << sizeof(Student) << endl;
return 0; }
|
联合体内部公用一块内存空间,所以内部占用空间按照最大的数据类型来存储,联合体适合内存受限的场景,比如嵌入式系统。也因为这个原因,同一时间只有一个成员有效,写入一个成员时会覆盖其他成员。
空结构体(不含数据成员)的大小是1,不是0。编译器必须要为其分配一个存储空间用于占位。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| struct s1 { char x; int z; short y; };
sizeof(s1) = 12;
struct s2 { char x; short y; int z; };
sizeof(s2) = 8;
|

- 结构体的每个成员在内存中的起始地址必须满足其类型的对其要求,32位系统要求如下:
- char:任何地址
- short:偶数倍地址
- int:4的整数倍、
- float:4的整数倍
- double:8的整数倍
- 指针:4的整数倍
可以看到,如果结构体中存在一个double,则会按照8字节来对齐。然后所有成员按照顺序依次分配内存,编译器会在成员之间插入填充字节,确保下一个成员满足对齐要求。如果存在结构体嵌套,也按照这个对齐规则,所有结构体中的最大成员值来进行内存对齐。结构体的总大小波许是最大成员对齐值的整数倍。
有一点需要注意,如果结构体中存放了一个数组,数组是按照单个变量一个一个摆放的,不要把数组视为一个整体。
程序是可以修改默认编译选项的,修改结构体内存分配,如果设置为1,那就是连续的内存分配布局:
1 2 3 4 5 6 7 8 9 10
| Visual C++: #pragma pack(push) #pragma pack(n)
#pragma pack(pop)
g++: __attribute__(aligned(n)) __attribute__(__packed__)
|