Is there a way in gcc, where I could define a struct with a specific member in a specific offset?
I want to define a struct in the following way:
struct {
.offset(0xDC) //or something equivalent
int bar;
} foo;
and then the following statement:
int a = foo.bar
will be identical to the statement:
int a = *(int*)((char*)&foo + 0xDC);
* UPDATE *
Some background: I want to access members in an exported struct which I have no proper definition, it has many members - which I care about only a handful of them, and their offset (the struct original definition) is a bit different on each target platform (I need to compile my code for a few different platforms)
I have considered the padding option mentioned on the comments here, but it requires me to do some annoying calculations each time I want to add a member. for example:
strcut {
.offset(0xDC)
int bar;
.offset(0xF4)
int moo;
}foo;
is simpler then:
struct __attribute__ ((__packed__)) struct {
char pad1[0xD8];
int bar;
char pad2[0x18];
int moo;
}foo;
and that without taking into consideration the fact the sizeof(int) can change from platform to platform
You should have a look at __attribute__ ((__packed__))
.
In your case you would write:
struct __attribute__ ((__packed__)) {
char unused[0xDC];
int bar;
} foo;
If you could explain what you're trying to do there may be other, possibly more elegant, solutions.
A solution using padding and union as proposed in other answers:
#include <stdio.h>
#define OFF_STRUCT(name, members) union { members } name
#define OFF_MEMB(offset, member) \
struct __attribute__ ((__packed__)) { \
char pad[offset]; \
member; \
}
int main(int argc, char *argv[])
{
OFF_STRUCT(foo,
OFF_MEMB(0xD8, int bar);
OFF_MEMB(0x18, double moo);
OFF_MEMB(0x1, int bee);
);
printf("offset: 0x%x 0x%x 0x%x\n",
(void*)&foo.bar - (void*)&foo,
(void*)&foo.moo - (void*)&foo,
(void*)&foo.bee - (void*)&foo
);
}
Output:
offset: 0xd8 0x18 0x1
You can always pad it with bytes and make sure that you tell gcc not to align your structs (as this may throw off the offsets). In that case you would need a member like char pad_bytes[num_pad_bytes];
. Although is there a reason to really do this? You can always calculate the offset of a member of a struct by doing some pointer arithmetic.
Note: you may want to use the uint8_t
type to pad instead of char as some compilers may actually pad char (which is usually a byte) to the size of a word.
Calculating offset is as simple as
size_t offset = (size_t)&((struct_type *)0)->member);
All this does is simply return a pointer to where member would be in struct_type if the struct were at 0x00 in memory (which it can never be) but since we use 0 as a base then the offset is simply the reference returned by the & operator.
I'd write a class that wraps a pointer:
class whateverPtr {
unsigned char *p;
public:
whateverPtr(void *p) : p(reinterpret_cast<unsigned char *>(p) { }
uint32_t getBar() const { return read_uint32(0xdc); }
private:
uint32_t read_uint32(unsigned int offset) {
return p[offset] |
(p[offset + 1] << 8) |
(p[offset + 2] << 16) |
(p[offset + 3] << 24);
}
};
This is fully portable and will work as expected on bigendian architectures. Signed integers are a bit trickier as you need to get the encoding right.
I have considered the padding option mentioned on the comments here, but it requires me to do some annoying calculations each time I want to add a member.
Regarding annoying calculations, you can just generate the declaration of your struct using your preferred scripting language:
struct = { 0xdc : (4, 'int bar'),
0xf4 : (4, 'int moo') }
def print_struct_decl (name, decl):
print "struct __attribute__ ((packed)) %s {" % name
off = 0
i = 0;
for o in sorted (decl.keys()):
print "\tchar pad%d [%d];" % (i, o - off)
i = i + 1
off = off + o + decl[o][0]
print "\t%s;" % decl[o][1]
print "};"
print_struct_decl ("whatever", struct)
Outputs:
struct __attribute__ ((packed)) whatever {
char pad0 [220];
int bar;
char pad1 [20];
int moo;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With