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

では、 in Message をtypemain.cppにキャストしました。ポイントは、レイアウトに従ってメモリにアクセスできることです。m_bufferHeaderHeader

#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 msgm_primitiveは と同じアドレスにあると想定されHeader* hdrm_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異なるタイプのポインターにキャストすることにより、クラスのタイプに応じてレイアウトを変更することになっています。

また、コピーが返された場合、 の値はm_primitive100 になるm_transNumはずです。しかし、値は間違っています。memcpychar* contentmsg

4

2 に答える 2

2

あなたprimitive()transNum()関数はメンバー変数への参照を返さず、コピーを返します。もちろん、コピーのアドレスはオリジナルと同じではありません。

于 2012-02-14T04:40:15.003 に答える
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デストラクタを持っているのを見ましたHeadervtableインサイダーHeaderオブジェクトへのポインタがあるため、上記は機能しません。配置される場所はコンパイラ固有です。いくつかの実験を試して、それに応じてオフセットを調整することができます。

于 2012-02-14T04:44:24.080 に答える