简介
标准库
预处理指令
#pragma pack()
#pragma pack
是C/C++中用于控制结构体(struct),联合体(union)和类(class)成员内存对齐的预处理指令。通过调整对齐方式,可以优化内存使用或兼容特定硬件/协议的数据布局要求。设置对齐值:
#pragma pack(n)
- 指定成员的对齐字节数为 n,常见值为1,2,4,8,16
1
2
3
4
5
6
7
struct MyStruct {
char a;
int b;
short c;
};
- 指定成员的对齐字节数为 n,常见值为1,2,4,8,16
保存和恢复对齐状态: push和pop
- 用于临时修改对齐方式后恢复之前的设置
1
2
3
4
5
6
struct Example {
char a;
int b;
};
- 用于临时修改对齐方式后恢复之前的设置
对齐规则
- 成员对齐值:每个成员的对齐值为 min(n, 自然对齐值)
- 自然对齐值通常是成员自身大小(例如int为4字节)
- 若n = 1,所有成员紧密排列,无填充
- 结构体总大小:必须是 最大成员对齐值 的倍数。
- 成员对齐值:每个成员的对齐值为 min(n, 自然对齐值)
默认对齐(假设4字节)
1
2
3
4
5
6struct DefaultAlign {
char a; // 1 字节
int b; // 4 字节(需对齐到 4 的倍数,a 后填充 3 字节)
short c; // 2 字节(结构体总大小需为 4 的倍数,c 后填充 2 字节)
};
// 总大小 = 1 + 3(填充) + 4 + 2 + 2(填充) = 12 字节1字节对齐
1
2
3
4
5
6
7
8
struct PackedAlign {
char a; // 1 字节
int b; // 4 字节(无需填充)
short c; // 2 字节
};
// 总大小 = 1 + 4 + 2 = 7 字节应用场景:
- 减少内存占用:通过紧密排列节省空间(尤其在嵌入式系统中)
- 兼容性需求:确保数据布局与硬件,协议或文件格式一致(例如网络协议头)
- 跨平台数据交换:消除不同编译器默认对齐带来的差异。
注意事项
- 性能影响:过度使用 #pragma pack(1) 可能导致非对齐内存访问,降低性能
- 可移植性:不同编译器可能对默认对齐的处理不同,跨平台代码需谨慎
- 与编译选项结合:如 GCC 的 attribute((packed)) 或 MSVC 的 __declspec(align(n))
- 二进制兼容性:直接读写结构体二进制时,还需考虑字节序(大端/小端)问题
#pragma warning()
#pragma warning是C/C++中用于控制编译器警告的预处理指令,主要针对MSVC(Microsoft Visual C++)编译器。通过该指令,开发者可以灵活的禁用,启用或修改特定警告的行为,从而优化编译输出或解决代码兼容性问题。
禁用/启用单个警告
1
2
3使用 push 和 pop 操作可以临时修改警告设置,并自动恢复之前的配置
1
2
3
4
// ... 部分代码 ...批量操作
1
2注意事项
- 不要滥用:过度禁用警告可能掩盖潜在代码问题
- 跨平台兼容性:#pragma warning 是MSVC特有指令,其他编译器(例如GCC/Clang)需使用其他方式
- GCC/Clang: #pragma GCC diagnostic ignored “-W警告名称”
- 作用域限制: #pragma warning 的作用域为当前文件,且从声明位置开始生效
- 优先级:编译器的 /Wn 选项(例如/W0 禁用所有警告)会覆盖 #pragma warning
#pragma push_macro()
#pragma push_macro() 是C/C++中用于临时保存和恢复宏定义的预处理指令,主要用于在代码块中临时修改宏定义并恢复原始状态。它在处理宏冲突,兼容第三方库或控制宏作用域时非常有用。
保存宏定义:#pragma push_macro(“宏名称”)
- 将当前宏的定义状态(包括是否已定义及其值)压入内部栈
恢复宏定义:#pragma pop_macro(“宏名称”)
- 从栈中弹出最近的宏定义状态并恢复
1
2
3
4
5
6
7
8
9
10
11
// 在此区域中 VALUE = 200
// 恢复后 VALUE = 100
- 从栈中弹出最近的宏定义状态并恢复
核心功能:
- 避免宏污染:在特定代码段内修改宏,不影响全局或其他代码
- 兼容性处理:解决与第三方库或系统头文件的宏冲突
- 精准控制宏作用域:类似栈的操作(先进后出),支持嵌套保存和恢复
解决宏命名冲突:
- 当系统头文件(如 Windows API)定义了通用名称的宏(如 max/min)时,可通过 push_macro 临时禁用:
1
2
3
4
5
6
7
8
9
- 当系统头文件(如 Windows API)定义了通用名称的宏(如 max/min)时,可通过 push_macro 临时禁用:
临时覆盖宏定义
- 在测试或调试时临时修改宏行为
1
2
3
4
5
6
7
8
9
// 执行无需调试的代码
- 在测试或调试时临时修改宏行为
兼容旧代码
- 当旧代码依赖已被废弃的宏时,可局部恢复旧定义
1
2
3
4
5
6
7
// 调用旧代码
old_function(); // 内部使用 OLD_MACRO
- 当旧代码依赖已被废弃的宏时,可局部恢复旧定义
注意事项:
- 配对使用:push_macro和pop_macro必须成对出现,否则可能导致未定义行为
- 作用域限制:虽然预处理指令不受代码块作用域限制,但通常建议在文件或模块级别使用
- 编译器支持:
- MSVC:完全支持
- GCC/Clang:需高版本支持(GCC 4.4+,Clang 2.9+)
- 宏名需为字符串字面量:必须用双引号包裹宏名称(如 “VALUE”)
#pragma GCC system_header
- #pragma GCC system_header 是GCC编译器特有的预处理指令,用于将当前文件标记为系统头文件。这一指令会影响编译器对代码的警告和错误处理策略,通常用于抑制第三方库或系统头文件中的非关键警告,使编译输出更简洁。
- 核心作用
- 抑制警告:标记为系统头文件后,GCC会忽略其内部的绝大多数警告(例如未使用变量,类型转换等),但保留致命错误(例如语法错误)
- 兼容性处理:避免第三方头文件中的代码因编译选项(例如-Wall, -Wextra)产生干扰性警告
- 行为模拟:让自定义头文件的行为与系统头文件一致。
- 工作原理:
- 作用范围:从 #pragma GCC system_header 出现的位置开始,到当前文件结束
- 警告过滤:GCC对系统头文件中的代码应用更宽松的警告策略,类似于编译时添加了-isystem选项(但优先级更高)
- 层级影响:若在头文件 A 中标记 system_header,则所有通过 #include 包含 A 的文件也会继承此行为。
- 注意事项:
- 谨慎使用:过度使用会掩盖潜在代码问题,建议仅用于稳定且可信的代码
- 作用域限制:仅对当前文件有效,不影响其他文件
- 编译选项优先级:
- 若使用 -Wsystem-headers 编译选项,GCC 仍会显示系统头文件中的警告
- 若使用 -isystem 指定头文件路径,其行为与 #pragma GCC system_header 类似,但后者优先级更高
- 非标准特性:此指令是 GCC 扩展,其他编译器(如 MSVC、Clang)可能不支持。Clang 部分兼容,但行为可能不同
- 不可嵌套:无法通过 push/pop 机制恢复状态,需通过文件作用域管理。
string文件
- string 类型是 basic_string
的别名。wstring 类型是 basic_string 的别名。 - 不同类型的字符串类(string, u8string, u16string, u32string, wstring)都是基于 basic_string
,唯一不同的是T的类型(char, char8_t, char16_t, char32_t, wchar_t) - 深入学习 std::string , 就需要深入学习 std::basic_string<>
bacis_string
std::string::size() 和 std::string::length()
- 两者都是返回成员变量: std::basic_string::_M_string_length
std::string::max_size()
- 返回可能存放的最大字符数量
resize()
void resize(size_type __n, _CharT __c);
- 这个函数将 std::string 缩放到指定的长度 __n 并使用 __c 填充.
- 当 __n 小于 std::string 的当前大小时,删除超出的。
void resize(size_type __n);
- 内部调用的是 this->resize(__n, _CharT()); 这表示使用默认字符 0 来进行对 std::string 的缩放。
shrink_to_fit()
- void shrink_to_fit();
- 内部调用: reserve();
- 将 capacity() 减少到 size()。
capacity()
- size_type capacity();
- 返回 std::string 在需要申请内存之前能够存放的总字符数。
reserve()
- void reserve(size_type __res_arg)
- 尝试使用指定的字节数预分配足够的内存资源。如果要申请的字节数大于 max_size() 则会抛出异常 std::length_error
clear()
- void clear();
- 擦除字符串,使其变为空
- 内部调用的是 _M_set_length(0); 这个函数内部动作是 将成员变量 _M_string_length 赋值为0;调用 traits_type::assign()将成员变量 _M_dataplus 设置为0.
empty()
- bool empty();
- 返回 size() == 0 的判定结果。
operator[]
- const_reference operator[] (size_type __pos) const;
- 内部先调用断言: __glibcxx_assert(__pos <= size()); 判断下标是否超出界限。
- 再直接进行数组的下标访问: _M_data()[__pos];
at()
- const_reference at(size_type __n) const;
- 内部先对 __n 进行判断,如果大于等于 size(),则手动抛出一个超出范围的异常。
- 如果小于size(),则正常进行数组的下标访问。
front()
back()
operator+=()
- basic_string& operator+=(const basic_string& __str);
- 内部就是调用 append(__str);