从结构中形成16位字

时间:2014-07-10 08:46:30

标签: c++ c struct

所以我正在创建一个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位字

2 个答案:

答案 0 :(得分:1)

符合标准的方法是通过memcpy

icmpPacket packet = { /* ... */ };
uint16_t buf[sizeof(icmpPacket) / sizeof(uint16_t)];
memcpy(buf, &packet, sizeof(icmpPacket));
/* Now use buf */

现代编译器足够聪明,可以适当地优化它,而无需实际执行函数调用。请参阅clangg++)的示例。

通用编译器扩展允许您使用联合,但这是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位指针

  • 但您需要将对齐添加到结构元素的 1 Byte !!!
  • 在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位数据类型...