所以我正在创建一个ICMPv4 echo请求,并决定使用自己的struct来保存数据包。为了在wireshark中识别容易识别的数据包,我决定将abcde放入数据字段。
struct icmpPacket{
u_int8_t icmp_type:8, icmp_code:8;
u_int16_t icmp_checksum:16, icmp_id:16, icmp_seqnum:16;
char icmp_data[6]; //cheat a little bit, set the field just large enough to store "abcde";
} __attribute__((aligned (16))) icmppckt; // icmp has an 8 byte header + 6 bytes of data
我遇到的问题是如何使编译器将结构读出为一系列16位字
答案 0 :(得分:1)
符合标准的方法是通过memcpy
:
icmpPacket packet = { /* ... */ };
uint16_t buf[sizeof(icmpPacket) / sizeof(uint16_t)];
memcpy(buf, &packet, sizeof(icmpPacket));
/* Now use buf */
现代编译器足够聪明,可以适当地优化它,而无需实际执行函数调用。请参阅clang和g++)的示例。
通用编译器扩展允许您使用联合,但这是undefined behavior under the C++ standard:
union packet_view{
icmpPacket packet;
uint16_t buf[sizeof(icmpPacket) / sizeof(uint16_t)];
};
icmpPacket packet = { /* ... */ };
packet_view view;
view.packet = packet;
/* Now read from view.buf. This is technically UB in C++ but most compilers define it. */
使用reinterpret_cast<uint16_t*>(&packet)
或其C等效项将破坏严格的别名规则并导致未定义的行为。 §3.10[basic.lval] / p10的C ++标准:
如果程序试图通过访问对象的存储值 行为是除以下类型之一以外的glvalue 未定义:
- 对象的动态类型,
- 对象的动态类型的cv限定版本,
- 与对象的动态类型相似的类型(如4.4中所定义)
- 与对象的动态类型对应的有符号或无符号类型的类型
- 与对象的动态类型的cv限定版本对应的有符号或无符号类型的类型,
- 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括, 递归地,子聚合的子元素或非静态数据成员 包含联盟),
- 一种类型,它是对象动态类型的(可能是cv限定的)基类类型,
- char或unsigned char类型。
同样,C11的§6.5/ p7说:
对象的存储值只能由左值访问 具有以下类型之一的表达式:
- 与对象的有效类型兼容的类型
- 与对象的有效类型兼容的类型的限定版本,
- 与对象的有效类型对应的有符号或无符号类型
- 与对象的有效类型的限定版本对应的有符号或无符号类型的类型,
- 一种聚合或联合类型,包括其成员中的上述类型之一(包括递归地,一个成员) subaggregate或contains union),或
- 字符类型。
答案 1 :(得分:0)
你可以使用16位指针
在C ++中你可以这样做:
#pragma pack(1)
struct icmpPacket
{
u_int8_t icmp_type:8, icmp_code:8;
u_int16_t icmp_checksum:16, icmp_id:16, icmp_seqnum:16;
char icmp_data[6]; //cheat a little bit, set the field just large enough to store "abcde";
} icmppckt; // icmp has an 8 byte header + 6 bytes of data
WORD *picmppckt16=(WORD*)((void*)&icmppckt);
#pragma pack()
将WORD更改为编译器知道的16位数据类型...