ASIO中icmp_header的operator>>为何硬编码读8字节而非sizeof(icmp_header)
问题背景
我在 asio-1.22.1/src/examples/cpp03/icmp/icmp_header.hpp 文件中看到了 asio::icmp_header 的如下实现:
class icmp_header { // 省略部分函数 friend std::istream& operator>>(std::istream& is, icmp_header& header) { return is.read(reinterpret_cast<char*>(header.rep_), 8); } // 省略部分函数 private: unsigned char rep_[8]; // 确实无其他成员变量 }
疑问
为什么不将该方法写成如下形式:
friend std::istream& operator>>(std::istream& is, icmp_header& header) { return is.read(reinterpret_cast<char*>(header.rep_), sizeof(icmp_header)); }
已知 class icmp_header 是无任何继承关系的简单类,原写法是为了规避不同操作系统下不可预期的结构体内存填充问题吗?
解答
你的判断完全正确,硬编码读取长度8的核心目的就是规避C++结构体内存布局的不确定性,同时严格匹配网络协议的标准定义:
- ICMP协议头部的固定长度就是8字节,这是RFC明确规定的协议标准值,和C++类的内存尺寸没有任何绑定关系。
- 即使当前类看起来只有一个长度为8的
unsigned char数组成员、无继承、无虚函数,C++标准也不保证类的大小完全等于成员的总大小:编译器可能出于平台对齐要求在结构体末尾插入填充字节,不同操作系统的ABI规则、不同编译选项(比如自定义对齐边界)都可能导致sizeof(icmp_header)的结果大于8。 - 如果用
sizeof(icmp_header)作为read的读取长度,会触发两类严重问题:- 读取长度超过
rep_数组的实际大小,造成内存越界写入,触发未定义行为 - 多读取了不属于ICMP头的后续载荷数据,后续解析协议字段时会得到错误结果
- 读取长度超过
- 这种写法还有额外的鲁棒性收益:即使后续代码维护时给类新增了其他私有成员(比如调试标记、解析状态字段),固定8字节的读取逻辑依然能正确工作,不会因为类尺寸变化出现逻辑错误或内存问题。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

