结构中的C ++可变长度数组 [英] C++ variable length arrays in struct

查看:177
本文介绍了结构中的C ++可变长度数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个用于创建,发送,接收和解释ARP数据包的程序.我有一个表示ARP标头的结构,如下所示:

I am writing a program for creating, sending, receiving and interpreting ARP packets. I have a structure representing the ARP header like this:

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的协议地址.地址长度也在标头中给出,因此,正确的结构必须看起来像这样:

This only works for hardware addresses with length 6 and protocol addresses with length 4. The address lengths are given in the header as well, so to be correct the structure would have to look something like this:

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 *)的接收字节数组,以便对其进行解释.

This obviously won't work since the address lengths are not known at compile time. Template structures aren't an option either since I would like to fill in values for the structure and then just cast it from (ArpHeader*) to (char*) in order to get a byte array which can be sent on the network or cast a received byte array from (char*) to (ArpHeader*) in order to interpret it.

一种解决方案是创建一个以所有标头字段作为成员变量的类,该函数创建代表可以在网络上发送的ARP标头的字节数组,以及一个仅包含字节数组的构造函数(在网络),并通过读取所有标头字段并将其写入成员变量来对其进行解释.不过,这不是一个很好的解决方案,因为它需要更多的代码.

One solution would be to create a class with all header fields as member variables, a function to create a byte array representing the ARP header which can be sent on the network and a constructor which would take only a byte array (received on the network) and interpret it by reading all header fields and writing them to the member variables. This is not a nice solution though since it would require a LOT more code.

相反,例如,由于所有标头字段均具有已知的恒定大小,因此类似的UDP标头结构很简单.我用

In contrary a similar structure for a UDP header for example is simple since all header fields are of known constant size. I use

#pragma pack(push, 1)
#pragma pack(pop)

围绕结构声明,这样我实际上可以进行简单的C样式强制转换,以获取要在网络上发送的字节数组.

around the structure declaration so that I can actually do a simple C-style cast to get a byte array to be sent on the network.

我是否可以在这里使用任何一种解决方案,而该解决方案应接近某个结构,或者至少不需要比该结构更多的代码? 我知道结构中的最后一个字段(如果是数组)不需要特定的编译时大小,是否可以为我的问题使用类似的内容?只是将这4个数组的大小保留为空将进行编译,但是我不知道这将如何实际起作用.只是从逻辑上讲这是行不通的,因为如果第一个数组的大小未知,编译器将不知道第二个数组在哪里开始.

Is there any solution I could use here which would be close to a structure or at least not require a lot more code than a structure? I know the last field in a structure (if it is an array) does not need a specific compile-time size, can I use something similar like that for my problem? Just leaving the sizes of those 4 arrays empty will compile, but I have no idea how that would actually function. Just logically speaking it cannot work since the compiler would have no idea where the second array starts if the size of the first array is unknown.

推荐答案

您想要一个相当低级的东西,一个ARP数据包,并且您正在尝试找到一种正确定义数据结构的方法,以便可以将blob投射到其中结构体.相反,您可以在Blob上使用接口.

You want a fairly low level thing, an ARP packet, and you are trying to find a way to define a datastructure properly so you can cast the blob into that structure. Instead, you can use an interface over the blob.

struct ArpHeader {
    mutable std::vector<uint8_t> buf_;

    template <typename T>
    struct ref {
        uint8_t * const p_;
        ref (uint8_t *p) : p_(p) {}
        operator T () const { T t; memcpy(&t, p_, sizeof(t)); return t; }
        T operator = (T t) const { memcpy(p_, &t, sizeof(t)); return t; }
    };

    template <typename T>
    ref<T> get (size_t offset) const {
        if (offset + sizeof(T) > buf_.size()) throw SOMETHING;
        return ref<T>(&buf_[0] + offset);
    }

    ref<uint16_t> hwType() const { return get<uint16_t>(0); }
    ref<uint16_t> protType () const { return get<uint16_t>(2); }
    ref<uint8_t> hwAddrLen () const { return get<uint8_t>(4); }
    ref<uint8_t> protAddrLen () const { return get<uint8_t>(5); }
    ref<uint16_t> opCode () const { return get<uint16_t>(6); }

    uint8_t *senderHwAddr () const { return &buf_[0] + 8; }
    uint8_t *senderProtAddr () const { return senderHwAddr() + hwAddrLen(); }
    uint8_t *targetHwAddr () const { return senderProtAddr() + protAddrLen(); }
    uint8_t *targetProtAddr () const { return targetHwAddr() + hwAddrLen(); }
};

如果需要const正确性,则删除mutable,创建const_ref,然后将访问器复制到非const版本中,并使const版本返回const_refconst uint8_t *

If you need const correctness, you remove mutable, create a const_ref, and duplicate the accessors into non-const versions, and make the const versions return const_ref and const uint8_t *.

这篇关于结构中的C ++可变长度数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆