假设我在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}}。但价值观是错误的。
答案 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
对象的指针,因此上述操作无效。放置的位置是编译器特定的。您可以尝试一些实验并相应地调整偏移量。