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.
The offsetof() macro is a compile-time construct. There is no standard-compliant way to define it, but every compiler must have some way of doing it.
One example would be:
#define offsetof( type, member ) ( (size_t) &( ( (type *) 0 )->member ) )
While not being a compile-time construct technically (see comments by user "litb"), every compiler must have at least one such expression that it is able to resolve at compile time, which is exactly what offsetof() is defined to in <stddef.h>.
There is probably some other error to your code - a missing include of <stddef.h>, or some other thing irritating your compiler.
It compiles without warning here with g++ 4, after I add the proper #includes.
Are you #including stddef.h? offsetof() is a macro, not a built-in keyword in C.
If that doesn't fix it, try making the constant static, to confine it to the module. That might make the compiler happy.
Using the standard #import <Foundation/Foundation.h> in your file will fix the problem.
Of course if you don't need any of the foundation classes, then do as others have said, include stddef.h.
offsetof is a macro contained in stddef.h. Add this line in your source file.
#import <stddef.h>
The offsetof() macro takes two arguments. The C99 standard says (in §7.17 <stddef.h>):
offsetof(type, member-designator)which expands to an integer constant expression that has type
size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that givenstatic type t;then the expression
&(t.member-designator)evaluates to an address constant.
So, you need to write:
offsetof(struct mystruct1, u_line.line);
However, we can observe that the answer will be zero since mystruct1 contains a union as the first (and only) member, and the line part of it is one element of the union, so it will be at offset 0.
Your struct mystruct1 has 1 member named u_line. You can see the offset of that member
offsetof(struct mystruct1, u_line); // should be 0
or of members down the line if you specify each "level of parenthood"
offsetof(struct mystruct1, u_line.line);
offsetof(struct mystruct1, u_line.line.buf);
offsetof(struct mystruct1, u_line.logo);