2

私はメモリ内に構造体を持っていますが、すべてのメンバーがまだわかっているわけではありません(この構造体はリバースエンジニアリングされています)。私がやりたいのは、次のような表現をメモリに保持することです。

struct Name {
    long Id;
    byte unknown[32];
    float X;
};

しかし、を非表示にしたいbyte unknown[32]ので、あるタイプの変数を使用しているときNameは、2つの変数IdとXしか表示できません。これは次のようになります。

struct Name {
    long Id;
    byte : 32*8; // So this doesn't appear
    float X;
};

しかし、これは機能しません1. 1行あたり8バイトに制限されているため、次のようになります。

struct Name {
    long Id;
    long long : 64;
    long long : 64;
    long long : 64;
    long long : 64;
    float X;
};

次に、実際にこれを実行しようとすると、期待どおりに機能しません(Xへのアクセスは構造体のオフセット0x24を参照しません)。

4

2 に答える 2

2

あなたは正しい道を進んでいますが、詳細が間違っているだけです。コンパイラは、ご使用のバージョンの にアラインメント パディングを挿入しましNameた。このプログラムはあなたが望むことをするかもしれません:

#include <cstddef>
#include <iostream>
#include <cassert>

struct Name {
    long Id;  // offset 0x00
    int : 32; // offset 0x04
    long long : 64;  // 0x08
    long long : 64;  // 0x10
    long long : 64;  // 0x18
    int : 32; // offset 0x20
    float X;  // offset 0x24
};

int main () {
  assert(sizeof(int) == 4);
  assert(sizeof(long) == 4);
  assert(sizeof(float) == 4);
  assert(sizeof(long long) == 8);
  assert(offsetof(Name, Id) == 0);
  assert(offsetof(Name, X) == 0x24);
}

または、調査することもできます#pragma pack

: あなたの問題に対する移植可能な、標準的に認可された解決策はありません。コンパイラは、パディング バイトを (ほぼ) どこにでも自由に挿入できます。ただし、上記の 2 つのような移植性のない、コンパイラが承認したソリューションが存在する場合があります。

于 2012-05-22T17:44:46.993 に答える
1

不明な構造の一般的な解決策を探している場合は、このコードを見てください

template <size_t SIZE> class UnknownStruct
{
public:
    enum {size = SIZE};
    explicit UnknownStruct(unsigned char* data)
    {
        memcpy(m_data, data, SIZE);
    }
    template <size_t OFFSET, typename TYPE> TYPE* read()
    {
        if(OFFSET + sizeof(TYPE) <= SIZE)
            return reinterpret_cast<TYPE*>(m_data + OFFSET);
        return NULL;
    }
private:
    unsigned char m_data[SIZE];
};

UnknownStructure は、関数でアクセスできる生のバイト (count SIZE) の blob ですread。問題に使用する方法の例を次に示します

class Name : public UnknownStruct<sizeof(long) + 32 + sizeof(float)>
{
public:
    explicit Name(unsigned char* data) : UnknownStruct<size>(data){}
    long& ID()
    {
        return *read<0, long>();
    }
    float& X()
    {
        return *read<sizeof(long) + 32, float>();
    }
};

呼び出しコードは次のようになります

unsigned char foodata[100] = {0};
Name fooreader(foodata);
fooreader.ID() = 57;
long id = fooreader.ID();

構造について理解が深まれば、適切なオフセットから型を読み取る関数を Name クラスに追加できます。

このコードの利点は、未知の構造に使用できることです。このソリューションを提供する他のライブラリがあるかもしれませんが、これは短くて簡単に使用できます

于 2012-05-22T20:24:25.093 に答える