Suppose I got this in 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
In main.cpp
, I casted the m_buffer
in Message into Header
type. The point is that I can access memory according to Header
layout:
#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;
}
The Header* hdr
is supposed to point to the same memory address as Message msg
, and the m_primitive
is supposed to be at the same address as Header* hdr
, and the m_transNum
is &m_primitive + 4
.
However, this is the actual value:
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
and m_transNum
pointed to a completely random location and got garbage values! How can it happen? reinterpret_cast
is supposed to change the layout according to class type, by casting to differnt type of pointer.
Also, if it returns a copy, the value of m_primitive
should be 100, and m_transNum
should be 1, because I memcpy
into the buffer char* content
of msg
. But the values are wrong.
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;
You are printing addresses of local stack variables to which you assigned values of your Header
data members. These addresses are not related to addresses of original variables.
Try (see EDIT below with regard to virtual
destructor)
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;
That's under assumption there is no padding. But enum
field size should be int
, usually. So it's 4 bytes and there is no padding. But check it to be sure.
EDIT: I just saw you have virtual
destructor in Header
. The above won't work, since there is a pointer to vtable
insider Header
object. Where it is placed is compiler specific. You can try some experimenting and adjust your offsets accordingly.