offsetof() of nested C struct in C++

3.5k Views Asked by At

I'm trying to add a socket filter to one of my sockets in C++ (Linux). In the socket filter I need to get the offset of struct fork_proc_event, which is nested within another structure. The definition looks like this (cn_proc.h):

struct proc_event {
    ...
    union {
        ...
        struct fork_proc_event {
            __kernel_pid_t parent_pid;
            ...
        } fork;
        ...
    } event_data;
    ...
};

In C I would do this:

int off = offsetof(struct fork_proc_event, parent_pid);

However I'm developing in C++. If I try to do this:

int off = offsetof(proc_event::fork_proc_event, parent_pid);

I get the following error:

error: expected type-specifier
error: expected `,'
error: expected `)' before ',' token

How should the offsetof() line look like?

2

There are 2 best solutions below

5
On BEST ANSWER

It may help to think of how an implementation of an offsetof macro might go. Here's one example:

#define offsetof(TYPE, MEMBER) \
    ((uintptr_t)&(((TYPE*)0)->MEMBER))

In other words, using 0 as a pointer to the type you're interested in, and simply taking the address of the struct field...

So if you wanted the offset of parent_pid relative to fork (which is how I initially parsed your question):

((char*)&((struct proc_event*)0)->event_data.fork.parent_pid) - ((char*)&((struct proc_event*)0)->event_data.fork)

On second reading it sounds like you might just want the offset of parent_pid relative to the start of struct proc_event. Adapting the example above that would be:

((uintptr_t)&((struct proc_event*)0)->event_data.fork.parent_pid)
1
On

I don't exactly understand the need for all those hacks, when all you have to do is give a name to your nested union type. Any name, just to be able to refer to it in C++ code

struct proc_event {
    ...
    union whatever {
        ...
        struct fork_proc_event {
            __kernel_pid_t parent_pid;
            ...
        } fork;
        ...
    } event_data;
    ...
};

Then you'll be able to refer to it as proc_event::whatever::fork_proc_event in offsetof in C++ code

size_t off = offsetof(proc_event::whatever::fork_proc_event, parent_pid);

If you are interested in offset of parent_pid from the beginning of proc_event, you can do

size_t off = offsetof(proc_event, event_data.fork.parent_pid);

If you cannot change the declaration, you can calculate the offset of parent_pid inside fork_proc_event by doing

size_t off = 
  offsetof(proc_event, event_data.fork.parent_pid) - 
  offsetof(proc_event, event_data.fork);

(Although I can't say right away whether the last two are formally legal examples of offsetof usage, they will normally work in practice without any problems.)