将char缓冲区转换为struct

时间:2016-08-18 11:24:49

标签: c++ pointers struct type-conversion unsigned-char

我有一个char缓冲区buf,其中包含buf[0] = 10buf[1] = 3buf[2] = 3buf[3] = 0buf[4] = 58

和结构:

typedef struct
{ 
    char type;
    int version;
    int length;
}Header;

我想将buf转换为Header。现在我正在使用函数

int getByte( unsigned char* buf)
{
    int number = buf[0]; 
    return number;
}

int getInt(unsigned char* buf)
{
    int number =  (buf[0]<<8)+buf[1];
    return number;
}

main()
{
    Header *head = new Header;
    int location = 0;

    head->type = getByte(&buf[location]);
    location++;     // location = 1

    head->version = getInt(&buf[location]);
    location += 2;  // location = 3

    head->ength = getInt(&buf[location]);
    location += 2;  // location = 5 
}

我正在寻找解决方案,例如

 Header *head = new Header;

 memcpy(head, buf, sizeof(head));

在此,Headerhead->type中的第一个值是正确的,其余是垃圾。是否可以将unsigned char* buf转换为Header

3 个答案:

答案 0 :(得分:4)

唯一完整的便携式和安全方式是:

void convertToHeader(unsigned char const * const buffer, Header *header)
{
    header->type = buffer[0];
    header->version = (buffer[1] <<  8) | buffer[2];
    header->length = (buffer[3] <<  8) | buffer[4];
}

void convertFromHeader(Header const * const header, unsigned char * buffer)
{
    buffer[0] = header->type;
    buffer[1] = (static_cast<unsigned int>(header->version) >>  8) & 0xFF;
    buffer[2] = header->version & 0xFF;
    buffer[3] = (static_cast<unsigned int>(header->length) >>  8) & 0xFF;
    buffer[4] = header->length & 0xFF;
}

Example

请参阅Converting bytes array to integer了解说明

修改

以前链接的快速摘要:其他可能的解决方案(例如memcpyunion)根据不同系统的字节顺序是不可移植的(做你做的事情可能是为了进行某种交流)至少两个异构系统)=&gt;一些系统byte [0]是int的LSB,而byte [1]是MSB而另一个是反向的。

此外,由于对齐,struct Header可能大于5个字节(在你的情况下可能是6个字节,如果对齐是2个字节!)(例如,参见here

最后,根据某些平台上的对齐限制和别名规则,编译器可能会生成错误的代码。

答案 1 :(得分:2)

您想要的是versionlengthbuf数组的2个元素具有相同的长度;您需要使用uint16_t中定义的<cstdint>类型,而不是int,这可能更长。此外,您还需要使buf成为uint8_t的数组,因为允许char超过1个字节!

您可能还需要将type移至最后;否则编译器几乎肯定会在它之后插入一个填充字节,以便能够将version对齐到一个2字节的边界(一旦你使它成为uint16_t,因此就是2个字节);然后你的buf[1]会在那里结束,而不是你想要它。 这可能就是你现在所观察到的,顺便说一下:通过char后跟int,可能是4个字节,你有3个字节的填充,并且数组的元素13正在那里插入(=永远丢失)。

另一种解决方案是将buf数组修改为更长并且还有空填充字节,以便数据实际上与struct字段对齐。

再次值得一提的是,正如评论中所指出的,sizeof(head)返回系统上指针的大小,而不是Header结构。你可以直接写sizeof(Header);但是在这种微观管理水平下,如果你只是写'5&#34;,那么你就不会失去更多的灵活性。

此外,字节顺序可以搞定你。处理器没有任何障碍来按照您期望的顺序存储数字的字节而不是相反的字节。毕竟两者都有内在意义。这意味着,如果数据类型为buf[0], buf[1],盲目地将字节(buf[0]<<8)+buf[1]复制到一个数字中会导致(buf[1]<<8)+buf[0],但也会导致(buf[1]<<24)+(buf[0]<<16),甚至4中的int字节(通常为int getTwoBytes(unsigned char* buf) { return (buf[0]<<8)+buf[1]; } main() { Header *head = new Header; head->type = buf[0]; head->version = getTwoBytes(buf + 1); head->length = getTwoBytes(buf + 3); } )。即使它现在可以在您的计算机上运行,​​但至少有一个相同的代码会导致垃圾。除非,即那些字节实际上来自首先重新解释数字。但是,在这种情况下,代码是错误的(不可移植)现在

......值得吗?

考虑到所有事情,我的建议是强烈地保持现在处理它们的方式。也许简化它。

将字节转换为int然后再转换为字节,或者取一个字节的地址再次取消引用它是没有意义的,也不需要没有描述性名称的辅助变量,除了存在之外没有任何目的返回,或者是您在任何时候事先知道其值的变量。

只做

Dim xl As Object
            xl = CreateObject("Excel.Application")
            Dim xwb As Object = xl.Workbooks.Open("C:\sahara\Code\OperationSummaryReport\Book1.xlsx")
            xwb.ActiveSheet.calculate()
            xwb.ActiveSheet.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, "C:\sahara\Code\OperationSummaryReport\sample.pdf", _
            XlFixedFormatQuality.xlQualityStandard, _
            True, _
            True, _
            1, _
            10, _
            True)


            xl.Quit()

答案 2 :(得分:-1)

更好的方法是创建某种序列化/反序列化例程。

另外,我不仅使用intchar类型,而且会使用更具体的int32_t等等。它只是与平台无关的方式(嗯,实际上你也可以打包)使用pragma pack的数据结构。)

    struct Header
    {
        char16_t type;
        int32_t version;
        int32_t length;
    };
    struct Tools
    {
        std::shared_ptr<Header> deserializeHeader(const std::vector<unsigned char> &loadedBuffer)
        {
            std::shared_ptr<Header> header(new Header);
            memcpy(&(*header), &loadedBuffer[0], sizeof(Header));
            return header;
        }
        std::vector<unsigned char> serializeHeader(const Header &header)
        {
            std::vector<unsigned char> buffer;
            buffer.resize(sizeof(Header));
            memcpy(&buffer[0], &header, sizeof(Header));
            return buffer;
        }
    }
    tools;
    Header header = {'B', 5834, 4665};
    auto v1 = tools.serializeHeader(header);
    auto v2 = tools.deserializeHeader(v1);