2. 结构体
1. 结构体的初始化与赋值
- C 语言中的 struct 定义了 一组变量的集合, C 语言中 struct 定义的标识符并不是一种新的类型。
- C++ 中的 struct 用于定义一个全新的类型。
1.1 初始化
两种,一种是 .field-name = value
,另一种是field-name:value
。
#include <iostream>
using namespace std;struct A {int b;int c;
};int main() {
/*A a = {.b = 5,.c = 10};
*/A a = {b:5,c:10};cout << a.b << endl; return 0;
}
- 构造函数初始化。struct 可以看成一个 class,结构体也可以拥有构造函数。struct 如果定义了构造函数,就不能用大括号进行初始化了。
#include <iostream>
using namespace std;struct A {A(int a, int b) {this->b = a;this->c = b;};int b;int c;
};int main() {struct A a(1,2);cout << a.b << endl;cout << a.c << endl;return 0;
}
1.2 赋值
结构体不能采用大括号的方式进行赋值(和初始化时的大括号不要混淆)。
#include <iostream>
using namespace std;struct A {int b;int c;
};int main() {struct A a;a = {1, 2}; // ❌ 编译报错return 0;
}
可以的方式:memset 置空;依次给每个成员变量赋值;使用已有的结构体变量直接赋值。
#include <iostream>
using namespace std;struct A {int b;int c;
};int main() {struct A a = {1,2};struct A aa;aa = a;cout << aa.b << endl;cout << aa.c << endl;return 0;
}
2. sizeof 计算结构体
2.1 内存对齐原则
- 首地址可以被最大宽度成员类型的大小整除
- 每个成员相对于首地址的偏移都是成员大小的整数倍,会填充字节
- 结构体总大小是最大宽度成员类型大小的整数倍,会填充字节
struct S1 {char c;int i;
};
sizeof(S1) = 1 + pad(3) + 4 = 8 bytes,pad(3) 表示填充 3 个字节。
struct S2 {char c1;S1 s;char c2;
};
sizeof(S2) = 1 + pad(3) + 8 + 1 + pad(3) = 16 bytes
2.2 修改对齐方式
#parameter pack(n)
中的 n 表示字节对齐数,默认是 8,取值可以是 1,2, 4,8,16。
#param pack(push) // 将当前pack设置压栈保存
#param pack(2)struct S1 {char c;int i;
};struct S2 {char c1;S1 s;char c2;
};#param pack(pop) // 恢复之前的pack设置
sizeof(S1) = 1 + pad(1) + 4 = 6 bytes
sizeof(S2) = 1 + 6 + 1 + pad(2) = 10 bytes
3. 空结构体
空结构体变量的大小是 1,编译器为其分配一字节的空间用于占位。
struct S3 { };
sizeof(S3) = 1 byte
4. 位域结构体
不需要占用一个完整的字节时,只需要占用一个或多个二进制位。
struct BitFieldStruct {int a:1; // 占用1位int :2; // 该两位不能使用int b:3;int c:2;
};
- 相邻位域字段的类型相同,会合到一起,没超过类型的大小,就合起来计算占用的空间。
- 相邻位域字段的类型相同,会合到一起,如果超过了类型的大小,则后面的字段从新的存储单元开始。
// 合起来不超过int类型的大小
#include <iostream>
using namespace std;struct BitFieldStruct {int a:1; // 占用1位int b:2;
};int main() {cout << sizeof(BitFieldStruct)<< endl;return 0;
}
结果是 4 字节。
#include <iostream>
using namespace std;struct BitFieldStruct {int a:1; // 占用1位int b:32;
};int main() {cout << sizeof(BitFieldStruct)<< endl;return 0;
}
结果是 8 字节。
5. sizeof 计算类
#include <iostream>
using namespace std;class Small {}; // 空类,占用1字节占位class LessFunc {int num;void func1() {};
};class MoreFunc {int num;void func1() {};int func2() {return 1;}
};class NeedAlign {char c;double d;int i;
};// 虚函数会在类中插入一个指向虚函数表的指针
class Virtual {int num;virtual void func() {};
};int main() {cout << sizeof(Small)<< endl;cout << sizeof(LessFunc)<< endl;cout << sizeof(MoreFunc)<< endl;cout << sizeof(NeedAlign)<< endl;cout << sizeof(Virtual)<< endl;return 0;
}
输出:1,4,4,24,16。