2012-05-22 104 views
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.因爲我再侷限於每行8個字節,因此它必須看起來像:

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

其次,當我真的嘗試這樣做時,它不能按預期工作(訪問X並不指向結構的偏移量0x24)。

+4

爲什麼你不能使用第一種形式,並使'未知''私人'? –

+0

答案很可能是編譯器特有的。你使用什麼編譯器? –

+0

只是給它一個更好的名字,像'this_is_padding_that_I_absolutely_will_not_use_Honest_Gov' –

回答

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

注意:沒有可移植的,標準認可的解決方案來解決您的問題。編譯器可以自由地插入填充字節(幾乎),無論他們選擇何種方式。但是,可能會有非便攜式,由編譯器認可的解決方案,比如上述兩種解決方案。

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是原始字節的BLOB(計數SIZE),你可以用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(); 

,你發現更多的結構,你可以添加更多的功能名稱類這將從適當的偏移量讀取類型

此代碼的優點是它可以用於任何未知的結構。可能有其他庫提供這種解決方案,但這是短而簡單的使用