Take the 2-minute tour ×

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);


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 {
    int bar;
    int moo;

is simpler then:

struct __attribute__ ((__packed__)) struct {
   char pad1[0xD8];
   int bar;
   char pad2[0x18];
   int moo;

and that without taking into consideration the fact the sizeof(int) can change from platform to platform

share|improve this question
Did you mean bit-fields ? –  iammilind Nov 23 '11 at 8:08
I think that no, and if you really want constant offsets, I'll do that with cast and pointers, like e.g. *((int*)(((char*)p)+0xd8)) which you could hide in a macro. –  Basile Starynkevitch Nov 23 '11 at 14:03

6 Answers 6

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.

share|improve this answer
I forgot to mention the packed attribute although I hinted at it +1 –  Jesus Ramos Nov 23 '11 at 8:28
with union on top. –  curiousguy Nov 23 '11 at 8:40
I m trying to write a code that runs on a few different platforms. I want to access a structure that is exported by a different module, not written by myself, and to which I have no headers. On each platform, the members I want to access are on different offsets, I want that offset to be a macro defined by the build system for each platform... Your solution I what I am currently using, but I wanted to know if there is anything clearer –  t_z Nov 23 '11 at 8:44
@t_z Actually I think this is the only way to do it unless you save this into a buffer and do the offsets from there which will get you the same result albeit more complicated looking. –  Jesus Ramos Nov 23 '11 at 8:48
@t_z I don't think that using a structure is the best choice; I would make a function (or more) to parse that structure depending on platform. This way I could avoid doing some compilation tricks, which in my opinion increases complexity of the build system. –  INS Nov 23 '11 at 9:34

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.

share|improve this answer
"All this does is simply" get undefined behaviour. You are dereferencing a null pointer! –  curiousguy Nov 23 '11 at 8:38
@curiousguy Nope actually, it doesn't actually dereference it because of the & operator. The generic linked list implementation in C uses this exact macro (in the linux kernel as well look for container_of macro). Here's the link for you just in case lxr.linux.no/#linux+v3.1.2/include/linux/stddef.h#L20 –  Jesus Ramos Nov 23 '11 at 8:39
@JesusRamos, in this case you should use the perfectly standard C99/C++98/C++11 macro offsetof. –  chill Nov 23 '11 at 9:56
"char (which is usually a byte)" A char by definition is a byte, so it needs no alignment (alignment = 1). –  curiousguy Nov 23 '11 at 11:59
"You can remove your downvote now :)" I can't. A dereference is a dereference, and UB is UB. *p is a dereference of p, and it is illegal if p does not point to an object. –  curiousguy Nov 23 '11 at 13:38


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)


struct __attribute__ ((packed)) whatever {
    char pad0 [220];
    int bar;
    char pad1 [20];
    int moo;
share|improve this answer

I don't suggest doing this; structures are not meant for this sort of data manipulation. If you need to modify data at a specific location, use a properly typed pointer to make the changes that way. Adding structures into the mix just adds complexity without any benefit.

share|improve this answer

I'd write a class that wraps a pointer:

class whateverPtr {
    unsigned char *p;

    whateverPtr(void *p) : p(reinterpret_cast<unsigned char *>(p) { }

    uint32_t getBar() const { return read_uint32(0xdc); }

    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.

share|improve this answer

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_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


offset: 0xd8 0x18 0x1
share|improve this answer

Your Answer


