Standard macro in the C programming language
C's offsetof() macro is an ANSI C library feature found in stddef.h. It evaluates to the offset (in bytes) of a given member within a struct or union type, an expression of … Wikipedia
🌐
Wikipedia
en.wikipedia.org › wiki › Offsetof
offsetof - Wikipedia
October 29, 2025 - It's possible a statement expression was used to ensure type safety and therefore eliminate potential accidental bugs. There is, however, a way to implement the same behaviour without using statement expressions while still ensuring type safety: #define CONTAINER_OF(ptr, Type, member) ((Type*)((char*)(1 ? (ptr) : &((Type*)0)->member) - offsetof(Type, member)))
🌐
GNU
gcc.gnu.org › onlinedocs › gcc › Offsetof.html
Offsetof (Using the GNU Compiler Collection (GCC))
primary: "__builtin_offsetof" "(" typename "," offsetof_member_designator ")" offsetof_member_designator: identifier | offsetof_member_designator "." identifier | offsetof_member_designator "[" expr "]"
🌐
Cppreference
en.cppreference.com › w › cpp › types › offsetof.html
offsetof - cppreference.com
March 26, 2024 - #include <cstddef> #include <iostream> struct S { char m0; double m1; short m2; char m3; // private: int z; // warning: 'S' is a non-standard-layout type }; int main() { std::cout << "offset of char m0 = " << offsetof(S, m0) << '\n' << "offset of double m1 = " << offsetof(S, m1) << '\n' << "offset of short m2 = " << offsetof(S, m2) << '\n' << "offset of char m3 = " << offsetof(S, m3) << '\n'; }
Top answer
1 of 4
51

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 ...

  1. Casting the value zero to the struct pointer type a*
  2. Getting the struct field b of this (illegally placed) struct object
  3. Getting the address of this b field
  4. 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.

2 of 4
21

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.

🌐
GitHub
gist.github.com › graphitemaster › 494f21190bb2c63c5516
Working around offsetof limitations in C++ · GitHub
offsetof in VIsual Studio is implemented as: #define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
🌐
TutorialsPoint
tutorialspoint.com › c_standard_library › c_macro_offsetof.htm
C library - offsetof() macro
The C library offsetof(type, member-designator) Macro results in a constant integer of type size_t which is the offset in bytes of a structure member from the beginning of the structure.
🌐
GeeksforGeeks
geeksforgeeks.org › c++ › the-offsetof-macro
The OFFSETOF() macro - GeeksforGeeks
July 23, 2025 - We know that the elements in a structure will be stored in sequential order of their declaration. How to extract the displacement of an element in a structure? We can make use of offsetof macro. Usually we call structure and union types (or classes with trivial constructors) as plain old data (POD) types, which will be used to aggregate other data types.
🌐
University of Chicago
naipc.uchicago.edu › 2015 › ref › cppreference › en › cpp › types › offsetof.html
offsetof - cppreference.com
#include <iostream> #include <cstddef> struct S { char c; double d; }; int main() { std::cout << "the first element is at offset " << offsetof(S, c) << '\n' << "the double is at offset " << offsetof(S, d) << '\n'; }
Find elsewhere
🌐
Wikibooks
en.wikibooks.org › wiki › C_Programming › stddef.h › offsetof
C Programming/stddef.h/offsetof - Wikibooks, open books for an open world
The offsetof() macro takes two parameters, the first being a structure name, and the second being the name of a member within the structure. It can not be described as a C prototype.[1] ... The "traditional" implementation of the macro relied on the compiler being not especially picky about ...
🌐
Linux Man Pages
man7.org › linux › man-pages › man3 › offsetof.3.html
offsetof(3) - Linux manual page
On a Linux/i386 system, when compiled using the default gcc(1) options, the program below produces the following output: $ ./a.out offsets: i=0; c=4; d=8 a=16 sizeof(struct s)=16 Program source #include <stddef.h> #include <stdio.h> #include <stdlib.h> int main(void) { struct s { int i; char c; double d; char a[]; }; /* Output is compiler dependent */ printf("offsets: i=%zu; c=%zu; d=%zu a=%zu\n", offsetof(struct s, i), offsetof(struct s, c), offsetof(struct s, d), offsetof(struct s, a)); printf("sizeof(struct s)=%zu\n", sizeof(struct s)); exit(EXIT_SUCCESS); }
🌐
Microsoft Learn
learn.microsoft.com › en-us › cpp › c-runtime-library › reference › offsetof-macro
offsetof Macro | Microsoft Learn
October 26, 2022 - The offsetof macro returns the offset in bytes of memberName from the beginning of the structure specified by structName as a value of type size_t.
Top answer
1 of 4
17

It's a builtin provided by the GCC compiler to implement the offsetof macro that is specified by the C and C++ Standard:

GCC - offsetof

It returns the offset in bytes that a member of a POD struct/union is at.

Sample:

struct abc1 { int a, b, c; };
union abc2 { int a, b, c; };
struct abc3 { abc3() { } int a, b, c; }; // non-POD
union abc4 { abc4() { } int a, b, c; };  // non-POD

assert(offsetof(abc1, a) == 0); // always, because there's no padding before a.
assert(offsetof(abc1, b) == 4); // here, on my system
assert(offsetof(abc2, a) == offsetof(abc2, b)); // (members overlap)
assert(offsetof(abc3, c) == 8); // undefined behavior. GCC outputs warnings
assert(offsetof(abc4, a) == 0); // undefined behavior. GCC outputs warnings

@Jonathan provides a nice example of where you can use it. I remember having seen it used to implement intrusive lists (lists whose data items include next and prev pointers itself), but I can't remember where it was helpful in implementing it, sadly.

2 of 4
15

As @litb points out and @JesperE shows, offsetof() provides an integer offset in bytes (as a size_t value).

When might you use it?

One case where it might be relevant is a table-driven operation for reading an enormous number of diverse configuration parameters from a file and stuffing the values into an equally enormous data structure. Reducing enormous down to SO trivial (and ignoring a wide variety of necessary real-world practices, such as defining structure types in headers), I mean that some parameters could be integers and others strings, and the code might look faintly like:

#include <stddef.h>

typedef stuct config_info config_info;
struct config_info
{
   int parameter1;
   int parameter2;
   int parameter3;
   char *string1;
   char *string2;
   char *string3;
   int parameter4;
} main_configuration;

typedef struct config_desc config_desc;
static const struct config_desc
{
   char *name;
   enum paramtype { PT_INT, PT_STR } type;
   size_t offset;
   int   min_val;
   int   max_val;
   int   max_len;
} desc_configuration[] =
{
    { "GIZMOTRON_RATING", PT_INT, offsetof(config_info, parameter1), 0, 100, 0 },
    { "NECROSIS_FACTOR",  PT_INT, offsetof(config_info, parameter2), -20, +20, 0 },
    { "GILLYWEED_LEAVES", PT_INT, offsetof(config_info, parameter3), 1, 3, 0 },
    { "INFLATION_FACTOR", PT_INT, offsetof(config_info, parameter4), 1000, 10000, 0 },
    { "EXTRA_CONFIG",     PT_STR, offsetof(config_info, string1), 0, 0, 64 },
    { "USER_NAME",        PT_STR, offsetof(config_info, string2), 0, 0, 16 },
    { "GIZMOTRON_LABEL",  PT_STR, offsetof(config_info, string3), 0, 0, 32 },
};

You can now write a general function that reads lines from the config file, discarding comments and blank lines. It then isolates the parameter name, and looks that up in the desc_configuration table (which you might sort so that you can do a binary search - multiple SO questions address that). When it finds the correct config_desc record, it can pass the value it found and the config_desc entry to one of two routines - one for processing strings, the other for processing integers.

The key part of those functions is:

static int validate_set_int_config(const config_desc *desc, char *value)
{
    int *data = (int *)((char *)&main_configuration + desc->offset);
    ...
    *data = atoi(value);
    ...
}

static int validate_set_str_config(const config_desc *desc, char *value)
{
    char **data = (char **)((char *)&main_configuration + desc->offset);
    ...
    *data = strdup(value);
    ...
}

This avoids having to write a separate function for each separate member of the structure.

🌐
SEI CERT
wiki.sei.cmu.edu › confluence › display › cplusplus › EXP59-CPP.+Use+offsetof()+on+valid+types+and+members
EXP59-CPP. Use offsetof() on valid types and members - SEI CERT C++ Coding Standard - Confluence
The macro offsetof(type, member-designator) accepts a restricted set of type arguments in this International Standard. If type is not a standard-layout class, the results are undefined. The expression offsetof(type, member-designator) is never type-dependent and it is value-dependent if and ...
🌐
Open-std
open-std.org › jtc1 › sc22 › wg21 › docs › papers › 2024 › p3407r0.html
Make idiomatic usage of `offsetof` well-defined
October 14, 2024 - Implementations are more constrained by the needs of their users, in this case, than by the availability of compiler engineers to implement the optimization. Similarly, the function f1 defined earlier could be given the following definition in C. The offset value will always be 0 in this case, so the subtraction can be omitted without changing the meaning. void f1(int* p) { (S*)((char*)p - offsetof(struct S, a[0]))->data = 2; }
🌐
Barr Group
barrgroup.com › blog › how-use-cs-offsetof-macro
How to Use C's offsetof() Macro
March 1, 2004 - The offsetof() macro returns the offset of the element name within the struct or union composite.
🌐
Cppreference
cppreference.net › cpp › types › offsetof.html
offsetof - cppreference.net
#include <cstddef> #include <iostream> struct S { char m0; double m1; short m2; char m3; // private: int z; // warning: 'S' is a non-standard-layout type }; int main() { std::cout << "offset of char m0 = " << offsetof(S, m0) << '\n' << "offset of double m1 = " << offsetof(S, m1) << '\n' << "offset of short m2 = " << offsetof(S, m2) << '\n' << "offset of char m3 = " << offsetof(S, m3) << '\n'; }