Ok, so you have your answer? First, a few questions to show you how the interview usually went:
- Did you just write down a number like 12?
- Did you use sizeof?
- What if the size of an integer is 8-bytes on one architecture and 4 bytes on another?
- What about structure packing? There’s probably a weird unused byte after the character array. How did you account for that?
- What if someone adds, removes, or reorders your class variables without telling you?
- Does your solution involve allocating or otherwise declaring an instance of a foo_t?
- Does your answer compile down to an O(1) operation?
The real answer is robust in the face of data changes, platform differences, and structure packing.
struct foo_t
{
int a;
float b;
char c[3];
void * zPtr;
};
The answer is:
<offset> = (int)&(((foo_t*)0)->zPtr)
We don’t need any instances of the type or even a whole function, and it reduces to a single integer constant at compile time. This code can be put inside of a macro, and even made more general so that it can get the offset from any data member of any structure:
#define MyOffset(TYPE, MEMBER) (int)&(((TYPE*)0)->MEMBER)
There are some variations on this code using simple subtraction as well as some formalizations using the ptr_diff type, but that’s getting into minutiae that starts to get tangential to the problem. I was interested in seeing if the candidate knew that structures and platforms have nuances that you won’t always know about at code-time. Next, I wanted to see if they knew how structures were addressed internally and that the compiler always knows the magic value they’re after; if only it could be coaxed out. Finally, I wanted to see if they knew enough about machine code and addressing modes to know that they weren’t actually dereferencing NULL in there, and it won’t crash.
But what about offsetof?
Ahh, I can already hear the more experienced engineers out there decrying my complete ignorance of the offsetof macro. No, I know it’s there, and if a candidate ever brought that fact up, I would just ask them to implement it – strangely, a few people knew the answer off the top of their heads, but no one has ever mentioned offsetof.