Переинтерпретированный указатель не указывает на правильную ячейку памяти - PullRequest
0 голосов
/ 14 февраля 2012

Предположим, я получил это в 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_primitive и m_transNum указали на совершенно случайное местоположение и получили значения мусора!Как это может случиться?reinterpret_cast предполагается изменить макет в соответствии с типом класса, приведя к другому типу указателя.

Кроме того, если он возвращает копию, значение m_primitive должно быть 100, а m_transNumдолжно быть 1, потому что я memcpy в буфер char* content из msg.Но значения неверны.

Ответы [ 2 ]

2 голосов
/ 14 февраля 2012

Ваши функции primitive() и transNum() не возвращают ссылку на переменные-члены, они возвращают копию .Конечно, копия не будет иметь тот же адрес, что и оригинал.

1 голос
/ 14 февраля 2012
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 insider Header объект. Место его размещения зависит от компилятора. Вы можете попробовать поэкспериментировать и соответственно скорректировать свои смещения.

...