R.. is correct in his answer to the second part of your question: this code is not advised when using a modern C compiler.
But to answer the first part of your question, what this is actually doing is:
(
(int)( // 4.
&( ( // 3.
(a*)(0) // 1.
)->b ) // 2.
)
)
Working from the inside out, this is ...
- Casting the value zero to the struct pointer type
a* - Getting the struct field b of this (illegally placed) struct object
- Getting the address of this
bfield - Casting the address to an
int
Conceptually this is placing a struct object at memory address zero and then finding out at what the address of a particular field is. This could allow you to figure out the offsets in memory of each field in a struct so you could write your own serializers and deserializers to convert structs to and from byte arrays.
Of course if you would actually dereference a zero pointer your program would crash, but actually everything happens in the compiler and no actual zero pointer is dereferenced at runtime.
In most of the original systems that C ran on the size of an int was 32 bits and was the same as a pointer, so this actually worked.
It has no advantages and should not be used, since it invokes undefined behavior (and uses the wrong type - int instead of size_t).
The C standard defines an offsetof macro in stddef.h which actually works, for cases where you need the offset of an element in a structure, such as:
#include <stddef.h>
struct foo {
int a;
int b;
char *c;
};
struct struct_desc {
const char *name;
int type;
size_t off;
};
static const struct struct_desc foo_desc[] = {
{ "a", INT, offsetof(struct foo, a) },
{ "b", INT, offsetof(struct foo, b) },
{ "c", CHARPTR, offsetof(struct foo, c) },
};
which would let you programmatically fill the fields of a struct foo by name, e.g. when reading a JSON file.
One of the ways I've used it in embedded systems is where I have a struct which represents the layout of non-volatile memory (e.g. EEPROM), but where I don't want to actually create an instance of this struct in RAM. You can use various nice macro tricks to allow you to read and write specific fields from the EEPROM, where offsetof does the work of calculating the address of a field within the struct.
With regard to 'evil', you have to remember that lots of stuff which was traditionally done in 'C' programming, particularly on resource-limited platforms, now looks like evil hackery when viewed from the luxurious surrounding of modern computing.
One legitimate use of offsetof() is to determine the alignment of a type:
#define ALIGNMENT_OF( t ) offsetof( struct { char x; t test; }, test )
It may be a bit low-level to need the alignment of an object, but in any case I'd consider this a legitimate use.