Reputation: 33
I have a structure in memory, but not all members are known yet (this struct is reverse engineered). What I want to do is have the representation in memory like:
struct Name {
long Id;
byte unknown[32];
float X;
};
But I want the byte unknown[32]
to be invisible, so when I am using something of type Name
I can only see the 2 variables Id and X. I think it's similar to:
struct Name {
long Id;
byte : 32*8; // So this doesn't appear
float X;
};
But this doesn't work 1. because I am then limited to 8 bytes per line so it would have to look like:
struct Name {
long Id;
long long : 64;
long long : 64;
long long : 64;
long long : 64;
float X;
};
And secondly, when I actually try to do this, it doesn't work as expected (accessing X doesn't refer to offset 0x24 of the struct).
Upvotes: 2
Views: 2974
Reputation: 3713
If you're looking for a generic solution for any unknown structure, have a look at this code
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 is a blob of raw bytes (of count SIZE) you can access with the read
function. Here's an example of how to use it for your issue
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>();
}
};
the calling code would look something like this
unsigned char foodata[100] = {0};
Name fooreader(foodata);
fooreader.ID() = 57;
long id = fooreader.ID();
as you discover more about the structure, you can add more functions to the Name class that will read types from appropriate offsets
The advantage of this code is it can be used for any unknown structure. There may be other libraries out there that provide this solution but this is short and simple enough to use
Upvotes: 1
Reputation: 168866
You are on the right track, but you just have the details wrong. The compiler inserted alignment padding into your version of Name
. This program might do what you want:
#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);
}
Alternatively, you might investigate #pragma pack
.
Note: There is no portable, standard-sanctioned solution to your problem. Compilers are free to insert padding bytes (almost) wherever and however they choose. But there may be non-portable, compiler-sanctioned solutions, such as the two above.
Upvotes: 2