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 - Usage of offsetof is limited to POD types in C++98, standard-layout classes in C++11, and more cases are conditionally-supported in C++17, otherwise it has an undefined behavior.
🌐
cppreference.com
en.cppreference.com › w › c › types › offsetof.html
offsetof - cppreference.com
March 26, 2024 - The macro offsetof expands to an integer constant expression of type size_t, the value of which is the offset, in bytes, from the beginning of an object of specified type to its specified subobject, including padding if any.
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.

🌐
TutorialsPoint
tutorialspoint.com › c_standard_library › c_macro_offsetof.htm
C library - offsetof() macro
The program demonstrates how to find the offset of a specific member within a structure using the offsetof() macro.
🌐
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); }
🌐
Linux Man Pages
linux.die.net › man › 3 › offsetof
offsetof(3): offset of structure member - Linux man page
offsetof() returns the offset of the given member within the given type, in units of bytes. C89, C99, POSIX.1-2001.
🌐
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 "]"
🌐
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.
🌐
Linuxcampus
linuxcampus.net › documentation › man-html › htmlman3 › offsetof.3.html
offsetof(3) — Linux manual pages
offsetof() returns the offset of the given member within the given type, in units of bytes. POSIX.1-2001, POSIX.1-2008, C89, C99.
Find elsewhere
🌐
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.
🌐
GeeksforGeeks
geeksforgeeks.org › c++ › the-offsetof-macro
The OFFSETOF() macro - GeeksforGeeks
July 23, 2025 - The ultimate goal is to extract displacement of the element. We will see practical usage of offsetof macro in liked lists to connect similar objects (for example thread pool) in another article. Article compiled by Venki. References: 1. Linux Kernel code. 2. https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/offsetof-macro?redirectedfrom=MSDN 3.
🌐
Cplusplus
cplusplus.com › reference › cstddef › offsetof
offsetof
No-throw guarantee: this macro never throws exceptions: noexcept(offsetof(type,member)) is always true.
🌐
Wikibooks
en.wikibooks.org › wiki › C_Programming › stddef.h › offsetof
C Programming/stddef.h/offsetof - Wikibooks, open books for an open world
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
🌐
Open-std
open-std.org › jtc1 › sc22 › wg21 › docs › papers › 2024 › p3407r0.html
Make idiomatic usage of `offsetof` well-defined
October 14, 2024 - A C++-only project would typically make ListNode a base class. Converting a ListNode* to a Foo* could then be done easily using static_cast, and offsetof would be unnecessary. This option is not available in C.
Top answer
1 of 4
11

There is no way to write a portable offsetof macro. You must use the one provided by stddef.h.

Regarding your specific questions:

  1. The macro invokes undefined behavior. You cannot subtract pointers except when they point into the same array.
  2. The big difference in practical behavior is that the macro is not an integer constant expression, so it can't safely be used for static initializers, bitfield widths, etc. Also strict bounds-checking-type C implementations might completely break it.
  3. There has never been any C standard that lacked stddef.h and offsetof. Pre-ANSI compilers might lack it, but they have much more fundamental problems that make them unusable for modern code (e.g. lack of void * and const).

Moreover, even if some theoretical compiler did lack stddef.h, you could just provide a drop-in replacement, just like the way people drop in stdint.h for use with MSVC...

2 of 4
9

To answer #2: yes, gcc-4* (I'm currently looking at v4.3.4, released 4 Aug 2009, but it should hold true for all gcc-4 releases to date). The following definition is used in their stddef.h:

#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)

where __builtin_offsetof is a compiler builtin like sizeof (that is, it's not implemented as a macro or run-time function). Compiling the code:

#include <stddef.h>

struct testcase {
    char array[256];
};

int main (void) {
    char buffer[offsetof(struct testcase, array[0])];
    return 0;
}

would result in an error using the expansion of the macro that you provided ("size of array ‘buffer’ is not an integral constant-expression") but would work when using the macro provided in stddef.h. Builds using gcc-3 used a macro similar to yours. I suppose that the gcc developers had many of the same concerns regarding undefined behavior, etc that have been expressed here, and created the compiler builtin as a safer alternative to attempting to generate the equivalent operation in C code.

Additional information:

  • A mailing list thread from the Linux kernel developer's list
  • GCC's documentation on offsetof
  • A sort-of-related question on this site

Regarding your other questions: I think R's answer and his subsequent comments do a good job of outlining the relevant sections of the standard as far as question #1 is concerned. As for your third question, I have not heard of a modern C compiler that does not have stddef.h. I certainly wouldn't consider any compiler lacking such a basic standard header as "production". Likewise, if their offsetof implementation didn't work, then the compiler still has work to do before it could be considered "production", just like if other things in stddef.h (like NULL) didn't work. A C compiler released prior to C's standardization might not have these things, but the ANSI C standard is over 20 years old so it's extremely unlikely that you'll encounter one of these.

The whole premise to this problems begs a question: If these people are convinced that they can't trust the version of offsetof that the compiler provides, then what can they trust? Do they trust that NULL is defined correctly? Do they trust that long int is no smaller than a regular int? Do they trust that memcpy works like it's supposed to? Do they roll their own versions of the rest of the C standard library functionality? One of the big reasons for having language standards is so that you can trust the compiler to do these things correctly. It seems silly to trust the compiler for everything else except offsetof.

Update: (in response to your comments)

I think my co-workers behave like yours do :-) Some of our older code still has custom macros defining NULL, VOID, and other things like that since "different compilers may implement them differently" (sigh). Some of this code was written back before C was standardized, and many older developers are still in that mindset even though the C standard clearly says otherwise.

Here's one thing you can do to both prove them wrong and make everyone happy at the same time:

#include <stddef.h>

#ifndef offsetof
  #define offsetof(tp, member) (((char*) &((tp*)0)->member) - (char*)0)
#endif

In reality, they'll be using the version provided in stddef.h. The custom version will always be there, however, in case you run into a hypothetical compiler that doesn't define it.

Based on similar conversations that I've had over the years, I think the belief that offsetof isn't part of standard C comes from two places. First, it's a rarely used feature. Developers don't see it very often, so they forget that it even exists. Second, offsetof is not mentioned at all in Kernighan and Ritchie's seminal book "The C Programming Language" (even the most recent edition). The first edition of the book was the unofficial standard before C was standardized, and I often hear people mistakenly referring to that book as THE standard for the language. It's much easier to read than the official standard, so I don't know if I blame them for making it their first point of reference. Regardless of what they believe, however, the standard is clear that offsetof is part of ANSI C (see R's answer for a link).


Here's another way of looking at question #1. The ANSI C standard gives the following definition in section 4.1.5:

     offsetof( type,  member-designator)

which expands to an integral 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 ).

Using the offsetof macro does not invoke undefined behavior. In fact, the behavior is all that the standard actually defines. It's up to the compiler writer to define the offsetof macro such that its behavior follows the standard. Whether it's implemented using a macro, a compiler builtin, or something else, ensuring that it behaves as expected requires the implementor to deeply understand the inner workings of the compiler and how it will interpret the code. The compiler may implement it using a macro like the idiomatic version you provided, but only because they know how the compiler will handle the non-standard code.

On the other hand, the macro expansion you provided indeed invokes undefined behavior. Since you don't know enough about the compiler to predict how it will process the code, you can't guarantee that particular implementation of offsetof will always work. Many people define their own version like that and don't run into problems, but that doesn't mean that the code is correct. Even if that's the way that a particular compiler happens to define offsetof, writing that code yourself invokes UB while using the provided offsetof macro does not.

Rolling your own macro for offsetof can't be done without invoking undefined behavior (ANSI C section A.6.2 "Undefined behavior", 27th bullet point). Using stddef.h's version of offsetof will always produce the behavior defined in the standard (assuming a standards-compliant compiler). I would advise against defining a custom version since it can cause portability problems, but if others can't be persuaded then the #ifndef offsetof snippet provided above may be an acceptable compromise.

🌐
Cprogramming
cboard.cprogramming.com › c-programming › 40936-offsetof.html
offsetof
June 20, 2003 - It seems to be suggesting that if you have offsetof(T,m), that the compiler can fail to warn you if T is not a struct/union, or m is not a member of T. But that would mean the compiler is broken in my opinion. In C99, offsetof() is defined as having a result type of size_t.
🌐
GitHub
gist.github.com › graphitemaster › 494f21190bb2c63c5516
Working around offsetof limitations in C++ · GitHub
The most common technique for getting this information is through the offsetof macro defined in stddef.h.
🌐
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 offsetof() macro is defined by the C Standard as a portable way to determine the offset, expressed in bytes, from the start of the object to a given member of that object.