【发布时间】:2014-11-14 07:00:42
【问题描述】:
我正在编写一个用于创建、发送、接收和解释 ARP 数据包的程序。我有一个表示 ARP 标头的结构,如下所示:
struct ArpHeader
{
unsigned short hardwareType;
unsigned short protocolType;
unsigned char hardwareAddressLength;
unsigned char protocolAddressLength;
unsigned short operationCode;
unsigned char senderHardwareAddress[6];
unsigned char senderProtocolAddress[4];
unsigned char targetHardwareAddress[6];
unsigned char targetProtocolAddress[4];
};
这仅适用于长度为 6 的硬件地址和长度为 4 的协议地址。地址长度也在标头中给出,因此要正确,结构必须如下所示:
struct ArpHeader
{
unsigned short hardwareType;
unsigned short protocolType;
unsigned char hardwareAddressLength;
unsigned char protocolAddressLength;
unsigned short operationCode;
unsigned char senderHardwareAddress[hardwareAddressLength];
unsigned char senderProtocolAddress[protocolAddressLength];
unsigned char targetHardwareAddress[hardwareAddressLength];
unsigned char targetProtocolAddress[protocolAddressLength];
};
这显然行不通,因为地址长度在编译时是未知的。模板结构也不是一个选项,因为我想填充结构的值,然后将其从 (ArpHeader*) 转换为 (char*) 以获得可以在网络上发送或转换的字节数组从 (char*) 到 (ArpHeader*) 接收到的字节数组,以便对其进行解释。
一个解决方案是创建一个将所有头字段作为成员变量的类,一个用于创建表示可在网络上发送的 ARP 头的字节数组的函数和一个仅采用字节数组的构造函数(在网络)并通过读取所有头字段并将它们写入成员变量来解释它。这不是一个好的解决方案,因为它需要更多的代码。
相反,UDP 标头的类似结构很简单,因为所有标头字段都具有已知的恒定大小。我用
#pragma pack(push, 1)
#pragma pack(pop)
围绕结构声明,这样我实际上可以进行简单的 C 风格转换来获取要在网络上发送的字节数组。
我可以在这里使用任何接近结构或至少不需要比结构更多代码的解决方案吗? 我知道结构中的最后一个字段(如果它是一个数组)不需要特定的编译时大小,我可以使用类似的东西来解决我的问题吗?只需将这 4 个数组的大小留空即可编译,但我不知道它实际上是如何工作的。从逻辑上讲它不能工作,因为如果第一个数组的大小未知,编译器将不知道第二个数组从哪里开始。
【问题讨论】:
-
如果最大地址大小为 6,你不能制作大小为 [6] 的数组,然后相应地解释它们吗?如果您想避免大量代码,这是最简单的解决方案。另一种选择是为所有地址使用一个固定长度的大数组,并编写一个函数来根据地址的长度准备一个字节数组
-
零长度数组或灵活数组成员不是有效的 C++。
-
为什么不使用 std::string 或 std::vector 作为结构成员?如果你使用结构,为什么不给它们功能呢?将代码划分为数据和程序与面向对象编程完全相反。您的问题本身听起来像是设计失败!
-
嗯,
operationCode之后的内存块的解释实际上取决于protocolType(IPv4/IPv6),对。我建议在此处放置一个不透明的占位符指针,并将其余部分解释为 mac 和 IP 地址的两个附加结构。与netinet/in.h结构定义中的处理类似。 -
重载
operator char*和ArpHeader(char* data)不适合您的需要吗?你已经试过了吗? AFAIK 然后真正的底层结构变得无关紧要。