Why is the offsetof macro necessary?
Asked Answered
A

3

10

I am new to the C language and just learned about structs and pointers.

My question is related to the offsetof macro I recently saw. I know how it works and the logic behind that.

In the <stddef.h> file the definition is as follows:

#define offsetof(type,member) ((unsigned long) &(((type*)0)->member))

My question is, if I have a struct as shown below:

struct test {
    int field1:
    int field2:
};

struct test var;

Why cannot I directly get the address of field2 as:

char * p = (char *)&var;
char *addressofField2 = p + sizeof(int);

Rather than writing something like this

field2Offset = offsetof (struct test, field2);

and then adding offset value to var's starting address?

Is there any difference? Is using offsetof more efficient?

Amphibolous answered 7/2, 2016 at 21:14 Comment(1)
If you are new to C, hands off offsetof and the like. You will not need it for normal programming, but only advanced features a beginner will very likely mess up. - Nop offence, but a very well meant warning!Selfexcited
A
7

The C compiler will often add extra padding bits or bytes between members of a struct in order to improve efficiency and keep integers word-aligned (which in some architectures is required to avoid bus errors and in some architectures is required to avoid efficiency problems). For example, in many compilers, if you have this struct:

struct ImLikelyPadded {
    int x;
    char y;
    int z;
};

you might find that sizeof(struct ImLikelyPadded) is 12, not 9, because the compiler will insert three extra padding bytes between the end of the one-byte char y and the word-sized int z. This is why offsetof is so useful - it lets you determine where things really are even factoring in padding bytes and is highly portable.

Acidulant answered 7/2, 2016 at 21:18 Comment(1)
As an addition, the only reason the implementation gets away with UB in the macro is that it is the implementation.Housebound
W
1

Unlike arrays, memory layout of struct is not always contiguous. Compiler may add extra bytes, in order to align the memory. This is called padding.

Because of padding, it us difficult to find location of member manually. This is also why we always use sizeof to find struct size.

offsetof macro let you find out the distance, offset, of a member of struct from the starting position of the struct.

One intelligent use of offsetof is seen in Linux kernel's container_of macro. This macro let you find out starting position of node given the address of member in a generic inclusive doubly linked list.

Woodworker answered 7/2, 2016 at 21:29 Comment(0)
A
1

As already mentioned in the other answers, padding is one of the reasons. I won't repeat what was already said about it.

Another good reason to use the offsetof macro and not manually compute offsets is that you only have to write it once. Imagine what happens if you need to change the type of field1 or insert or remove one or more fields in front of field2. Using your hand-crafted calculation you have to find and change all its occurrences. Missing one of them will produce mysterious bugs that are difficult to find.

The code written using offsetof doesn't need any update in this situation. The compiler takes care of everything on the next compilation.

Even more, the code that uses offsetof is more clear. The macro is standard, its functionality is documented. A fellow programmer that reads the code understands it immediately. It's not that easy to understand what the hand-crafted code attempts.

Aikoail answered 7/2, 2016 at 21:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.