Haspemulator
Haspemulator

Reputation: 11318

Member offset macro - need details

Please take a look at this macro. It is used in Symbian OS SDK, which compiler is based on GCC (< 4 version of it).

#ifndef _FOFF
#if __GNUC__ < 4
#define _FOFF(c,f)          (((TInt)&(((c *)0x1000)->f))-0x1000)
#else
#define _FOFF(c,f)          __builtin_offsetof(c,f)
#endif
#endif

I understand that it is calculating offset to specific class/struct member. But I cannot understand how that weird statement works - what is the constant 0x1000 and why is it there? Could somebody please explain this to me?

Upvotes: 1

Views: 421

Answers (3)

SigTerm
SigTerm

Reputation: 26439

Imo 0x1000 is just a randomly chosen number. It is not a valid pointer, and it you could probably use zero instead of it.

How it works:

  1. Casts 0x1000 into class pointer (pointer of type c). - (c*)0x1000
  2. Takes pointer to "f" member of class c - &(((c *)0x1000)->f)
  3. Casts it into TInt. ((TInt)&(((c *)0x1000)->f))
  4. Substracts integer value of pointer to base (0x1000 in this case) from integer value of pointer to c's member: (((TInt)&(((c *)0x1000)->f))-0x1000)

Becuase f isn't being written to, there is no accessViolation/segfault.

You could probably use zero instead of 0x1000 and discard subtraction (i.e. just use "((TInt)&(((c *)0x0000)->f))"), but maybe author thought think that subtracting base pointer from pointer to member is a more "proper" way than trying to directly cast pointer into integer. Or maybe compiler provides "hidden" class members that can have negative offset (which is possible in some compilers - for example Delphi Compiler (I know it isn't c++) provided multiple hidden "fields" that were located before "self"(analogue of "this") pointer), in which case using 0x1000 instead of 0 makes sense.

Upvotes: 2

Alex Martelli
Alex Martelli

Reputation: 882631

"If there was a member of struct c starting exactly at the (perfectly-aligned;-) address 0x1000, then at what address would the struct's member f be?" -- answer: the offset you're looking for, minus of course the hypothetical starting address 0x1000 for the struct... with the difference, AKA distance or offset, computed as integers, otherwise the automatic scaling in address arithmetic throws you off (whence the cast).

What parts of the expression, specifically, are giving you problems?

The inner part &(((c *)0x1000)->f) is "the address of member f of a hypothetical struct c located at 0x1000. Right in front of it is the cast (I assume TInt is some kind of integer type, of course), then the - 0x1000 to get the offset (AKA distance or difference between the address of the specific member of interest and the start of the whole structure).

Upvotes: 1

sje397
sje397

Reputation: 41862

It is working out the relative address of 'f' as a member of a class/struct at address 0x1000, and then subtracting 0x1000 so that only the difference between the class/struct address and the member function address is returned. I imagine a non-zero value (i.e. the 0x1000) is used to avoid null pointer detection.

Upvotes: 1

Related Questions