I would explain some more general points to take into account dealing with macros.
Macros in C are just text replacements, in the simplest form a macro is a text to be replaced by another text:
#define OldText NewText
A more advanced feature of macros is the possibility of passing parameters. In this case the text to search and replace is macro name, while the text in the parameters is replaced in the positions where the parameters names appears in the macro body:
#define macro1(par1, par2) par1 = par2;
In the last example if we write:
macro1(a, 4)
After file preprocessing we will get:
a = 4;
The number of parameters can even be variable, this declared using the elipsis and the special symbol __VA_ARGS__ that translates to the sequence of variable parameters:
#define PRINTMACRO(format, ...) printf(format, __VA_ARGS__);
In this case the line:
PRINTMACRO("string %s and int %d\n", string, a);
Afte preprocessor will lead to:
printf("string %s and int %d\n", string, a);
Now after this clarification, going back to your question the macro that made you perplex is not complicate as a 'macro', but is how it is write that made you perplex.
If this is the case let have a closer look to it. First of all get rid of teh macro capsule and let analyze the content:
((LONG)(LONG_PTR)&(((type *)0)->field))
Exam from the inside:
((type *)0) here we cast the value 0 (zero) as the address of a type variable (a pointer to variable). Up to now it can be any kind of variable, but will understand that is not so.
Infact extending:
(((type *)0)->field) we understand that we are getting the member 'field' from a pointer to a struct of type 'type', which address is 0.
Further on:
&(((type *)0)->field) we are getting the address of the member 'field' of a structure of type 'type' at address 0.
Just a consideration is required now: if a structure is considered at address 0, the address of each field is coincident with the field offset, in bytes, from the start of the structure. But an offset is a number, and here we got an address. This can create warnings on types compatibility during compilation. We need to cast the result to a number.
This is what we do now, we cast our address to a
LONG, but before we cast the result to a
LONG_PTR.
This is an MS macro, and it is crafted to work for 32 and 64 bits assemblies. That's why we cast it first to LONG_PTR:
(LONG_PTR)&(((type *)0)->field).
LONG_PTR is a type that guarantee to accept longs and pointers for any processor bitness so avoid compiler warnings.
Then the last step is to cast value to what an offset must be: a number.
((LONG)(LONG_PTR)&(((type *)0)->field))
The morale is don't worry about the macro it is C rules you have to follow to un derstand the code ;).
It is a good habit to always enclose each parameter and then the whole macro in braces to avoid any side effect from the expression (don't do this and soon or later you'll find why you have to :D).
Last, why all that braces?
Consider:
struct _tagstr
{
int a;
float b;
};
void *pStr;
...
*((float *)((char *)pStr + FIELD_OFFSET(struct _tagstr, b))) = 0.1;
It's alway better to strictly delimit parameters of macros.
I hope this will give some more lights on the issue.
P.S. consider my last example as an exercise ;)