2012-02-14 53 views
0

假设我在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,并且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_primitivem_transNum指着一个完全随机的位置,并获得垃圾值!怎么会发生? reinterpret_cast应该根据类的类型更改布局,通过投射到不同类型的指针。

此外,如果它返回一个拷贝,的m_primitive的值应为100,并且m_transNum应该为1,因为我memcpy到缓冲器的msgchar* content。但价值观是错误的。

回答

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对象。放置位置是编译器特定的。您可以尝试一些实验并相应地调整偏移量。

+0

我明白了。但是,我不明白,如果它返回一个副本,它不应该有垃圾值。当我将这些值输出时,值不正确。 – Amumu 2012-02-14 04:49:00

+0

非常抱歉。 'FCPMsg'应该是'Message','MsgHeader'应该是'Header'。请修复它以保持一致。 – Amumu 2012-02-14 04:55:30

+0

Mark在他的评论中回答说。 – lapk 2012-02-14 04:55:40

2

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

+0

啊对了,但是如果它返回一个副本,我怎么能在'm_primitive'和'm_transNum'中得到垃圾值? – Amumu 2012-02-14 04:43:23

+0

@Amumu,你的Header类中有一个虚函数,这意味着它将在布局中有一个不可见的vtable指针,可能在前面。你对对象的二进制布局做了太多的假设,并且遇到未定义的行为。 – 2012-02-14 04:51:12

+0

谢谢。你是对的。 – Amumu 2012-02-14 05:55:07