C ++操纵结构的原始数据

时间:2014-07-25 18:31:23

标签: c++ memory

我有一个简单的结构,如下所示:

struct Object 
{
    int x_;
    double y_;
};

我正在尝试操纵对象的原始数据,这就是我所做的:

int main()
{
    Object my_object;
    unsigned char* raw_data = reinterpret_cast<unsigned char*>(&my_object);

    int x = 10;
    memcpy(raw_data, &x, sizeof(x));
    raw_data += sizeof(x);

    double y = 20.1;
    memcpy(raw_data, &y, sizeof(y));


    Object* my_object_ptr = reinterpret_cast<Object *>(raw_data);


    std::cout << *(my_object_ptr).x << std::endl;    //prints 20       (expected 10)
    std::cout << *(my_object_ptr).y << std::endl;    //prints Rubbish  (expected 20.1)
}

我期待上面的代码可以工作,,,

真正的问题是什么?这甚至可能吗?

2 个答案:

答案 0 :(得分:2)

这可能是结构填充问题。如果你有double y_作为第一个成员,你可能已经看到了你的期望。如果在数组中使用struct,编译器将使用额外的字节填充结构以使对齐正确。试试

#pragma pack(4)

在结构定义之前。

Visual Studio的#pragma pack引用:http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx默认情况下,您的结构被打包为8个字节,因此在x_y_之间有一个4字节的填充。

阅读http://www.catb.org/esr/structure-packing/以真正了解正在发生的事情。

答案 1 :(得分:2)

您需要使用offsetof macro。还有一些问题,最重要的是你修改了raw_data指针,然后将修改后的值转换回Object*指针,导致未定义的行为。我选择删除raw_data修改(替代方法是不将其强制转换,而是直接检查my_object)。这是一个固定的代码,在评论中有解释:

#include <iostream>
#include <cstring> // for memcpy
#include <cstddef> // for offsetof macro

struct Object 
{
    int x_;
    double y_;
};

int main()
{
    Object my_object;
    unsigned char* raw_data = reinterpret_cast<unsigned char*>(&my_object);

    int x = 10;
    // 1st memcpy fixed to calculate offset of x_ (even though it is probably 0)
    memcpy(raw_data + offsetof(Object, x_), &x, sizeof(x));
    //raw_data += offsetof(Object, y_); // if used, add offset of y_ instead of sizeof x

    double y = 20.1;
    // 2nd memcpy fixed to calculate offset of y_ (offset could be 4 or 8, depends on packing, sizeof int, etc)
    memcpy(raw_data + offsetof(Object, y_), &y, sizeof(y));

    // cast back to Object* pointer
    Object* my_object_ptr = reinterpret_cast<Object *>(raw_data);


    std::cout << my_object_ptr->x_ << std::endl;    //prints 10
    std::cout << my_object_ptr->y_ << std::endl;    //prints 20.1
}