重新解释的指针不指向正确的内存位置

时间:2012-02-14 04:30:13

标签: c++ memory reinterpret-cast

假设我在Message.h中得到了这个:

#ifndef _MESSAGE_H_
#define _MESSAGE_H_
#include <stdio.h>
#include <string.h>
enum PRIMITIVE{
      MESSAGE_1 = 100,
      MESSAGE_2,
};

enum { MSG_SIZE_IN_BYTES = 1024 };

class Header{
    protected:
        Header(PRIMITIVE prim, u_int32 transNum) : m_primitive(prim), m_transNum(transNum) { }
    public:
        // access
        PRIMITIVE primitive() const { return m_primitive; }
        u_int32 transNum()  const { return m_transNum; }
        virtual ~Header(){}
    private:
        PRIMITIVE m_primitive;
        u_int32 m_transNum;
    };

class Message
{
public:
    Message() { reset(); }
    // access
    char* addr() { return reinterpret_cast<char*>(m_buffer); }
    const char* addr() const { return reinterpret_cast<const char*>(m_buffer); }
    u_int32 size() { return sizeof(m_buffer); }
    // msgs
    Header* msgHeader() { return reinterpret_cast<Header*>(addr()); }
    const Header* msgHeader() const { return reinterpret_cast<const Header*>(addr()); }
    // modify
    void reset() {
        memset(&m_buffer, 0, MSG_SIZE_IN_BYTES);
    }
private:
    u_int64 m_buffer[MSG_SIZE_IN_BYTES / sizeof(u_int64)];
};
#endif

main.cpp中,我将消息中的m_buffer转换为Header类型。关键是我可以根据Header布局访问内存:

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int main(int argc, char *argv[]){
    Message msg;

    char* content = msg.addr();
    int prim = 100;
    int trans_num = 1;

    memcpy(content, &prim, 4);
    memcpy(content+4, &trans_num, 4);       

    const Message::Header* hdr = msg.msgHeader();
    Message::PRIMITIVE hdr_prim = hdr->primitive();
    u_int32 hdr_transNum = hdr->transNum();

    cout << "Memory address of Message: " << &msg << endl;

    cout << "Memory address of Message buffer: " << (void*) msg.addr() << endl;             
    cout << "Memory address of content: " <<  content << endl;      

    cout << "Memory address of Header: " << hdr << endl;
    cout << "Memory address of m_primitive in Header: " <<  &hdr_prim << endl;
    cout << "Memory address of m_transNum in Header: " <<  &hdr_transNum << endl;

    cout << "Primitive in Header: " << prim << endl;        
    cout << "Trans num in Header: " << transNum << endl;
}

Header* hdr应指向与Message msg相同的内存地址,而m_primitive应与Header* hdr位于同一地址,{ {1}}是m_transNum

但是,这是实际值:

&m_primitive + 4

Memory address of Message: 0x699520 Memory address of Message buffer: 0x699520 Memory address of content: 0x699520 Memory address of Header: 0x699520 Memory address of m_primitive in Header: 0x7f2ec2f2738c Memory address of m_transNum in Header: 0x7f2ec2f27388 Primitive in Header: 1 Trans num in Header: 1953719668 m_primitive指向一个完全随机的位置并获得了垃圾值!怎么会发生? m_transNum应该根据类类型更改布局,方法是转换为不同类型的指针。

此外,如果它返回副本,则reinterpret_cast的值应为100,m_primitive应为1,因为我m_transNum进入memcpy的{​​{1}} {1}}。但价值观是错误的。

2 个答案:

答案 0 :(得分:2)

您的primitive()transNum()函数未返回对成员变量的引用,它们返回副本。当然,副本的地址与原始地址不同。

答案 1 :(得分:1)

Message::PRIMITIVE hdr_prim = hdr->primitive();
u_int32 hdr_transNum = hdr->transNum();

...

cout << "Memory address of m_primitive in Header: " <<  &hdr_prim << endl;
cout << "Memory address of m_transNum in Header: " <<  &hdr_transNum << endl;

您正在打印指定了Header数据成员值的本地堆栈变量的地址。这些地址与原始变量的地址无关。

尝试(请参阅下面关于virtual析构函数的编辑)

const Message::Header* hdr = msg.msgHeader();
Message::PRIMITIVE * hdr_prim = ( Message::PRIMITIVE * ) hdr;
u_int32 * hdr_transNum = ( u_int32 *) ( ( ( char * ) hdr ) + sizeof( Message::PRIMITIVE ) );

...

cout << "Memory address of m_primitive in Header: " <<  hdr_prim << endl;
cout << "Memory address of m_transNum in Header: " <<  hdr_transNum << endl;

假设没有填充。但enum字段大小通常应为int。所以它是4个字节,没有填充。但请检查一下。

编辑:我刚刚在virtual看到你有Header析构函数。由于存在指向vtable内部Header对象的指针,因此上述操作无效。放置的位置是编译器特定的。您可以尝试一些实验并相应地调整偏移量。