22

Regarding the C programming language...

Part of the question at C/C++ Structure offset states that "& does not always point at the first byte of the first field of the structure"

But looking over the "ANSI Rationale" at http://www.lysator.liu.se/c/rat/c5.html it states "no hole may occur at the beginning" in section 3.5.2.1 Structure and union specifiers. So I'm not sure if the "Rationale" is definitive but it does seem to contradict that part of that highly visible question.

So, which is it? Is the first field of a C structure always guaranteed to be at offsetof 0?

struct A
{
    int x;
};

struct B
{
    struct A myA;
    int y;
};

B myB;

Is &myB guaranteed to be the same as &(myB.myA) in a portable way?

(More concretely, the libev user-data trick at Libev, How to pass arguments to relevant callbacks and many other places does assume that the first field in the structure is at offsetof 0... is that really portable?)

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • 3
    I'm pretty sure it's true in C; in C++ it's true for standard-layout classes. – Kerrek SB May 10 '13 at 12:57
  • I'm *pretty* sure that it's true too, I just don't know the relevant standard to cite. Portability is my issue. This works on everything I've tried, but will this haunt me on a platform I haven't seen yet? –  May 10 '13 at 13:00
  • @KerrekSB: where is the vtable located? in the beginning? (C++) – Alexander Oh May 10 '13 at 13:00
  • @Alex This is specifically a C question, not C++, the context here is writing very portable and standard plain-C code. –  May 10 '13 at 13:02
  • @wilsonmichaelpatrick if very portable is your target. righting a very portable offsetof macro will not harm your portability. and you will love it, if you start to change your structure layout, because standard or not, then this assumption will bite you. – Alexander Oh May 10 '13 at 13:09
  • 2
    @Alex: Polymorphic classes are not standard layout. – Kerrek SB May 10 '13 at 13:16
  • Possible duplicate of [In C, does a pointer to a structure always point to its first member?](http://stackoverflow.com/questions/7312555/in-c-does-a-pointer-to-a-structure-always-point-to-its-first-member) – Ciro Santilli OurBigBook.com May 08 '16 at 09:48

1 Answers1

26

From the C99 standard section 6.7.2.1 bullet point 13:

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

The answer to your question is therefore yes.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • Thanks, that's the answer, I just didn't know what to search around for and my search-engine hits were misleading. I'll accept this in a moment when it lets me. –  May 10 '13 at 13:09
  • @wilsonmichaelpatrick One of the problems is that the C standards are not freely available on the Internet. You normally have to pay (quite a lot) for them. I managed to find a copy of C99 here http://www.open-std.org/jtc1/sc22/wg14/www/standards It's technically a working paper, but it is good enough. – JeremyP May 10 '13 at 13:25
  • @wilsonmichaelpatrick Just for excessive pedantry: that does not guarantee that `(uintptr_t)&myB == (uintptr_t)&myB.myA`. [But you'd need a deliberately evil implementation to not have that equality.] – Daniel Fischer May 10 '13 at 13:45
  • @DanielFischer What is the nature of the evil that makes `(uintptr_t)&myB` and `(uintptr_t)&myB.myA` different in the context you're *not* describing? :) –  May 10 '13 at 14:18
  • 1
    @wilsonmichaelpatrick For example, the pointer could hold the address of the _last_ byte in the pointed-to object. Conversion to `uintptr_t` preserves bit-pattern of the held address, `(uintptr_t)&myB == (uintptr_t)&myB.myA + sizeof (int)`. Evil enough? – Daniel Fischer May 10 '13 at 14:25
  • @DanialFischer Yeah that's evil. Even though the structure has fields whose "addresses that increase in the order in which they are declared", I guess if you reference the structure as a whole with a pointer to the end, then everything could be a *reverse* offset from that? Would offsetof() return a negative number for the first field in the structure in the situation you describe? (I'm not going to sweat the deliberately evil case, just for my own information.) What about casting a pointer to one structure to a pointer to a larger structure? Would an offset have to be added then? –  May 10 '13 at 14:33
  • 1
    @DanielFischer I don't think a scheme where a pointer points to the last byte of the object is allowed within C99. And it would certainly break the rule I quoted. – JeremyP May 10 '13 at 14:54
  • @JeremyP No, it wouldn't break the rule. When you convert the pointers from one type to the other, you have of course to adjust the address, so for example casting an `int32_t *` to an `int64_t *` would add 4 to the address. The rule says **suitably converted**, so direct casts, and casts via `void*` must work (also character pointers), but via `uintptr_t` need not work. – Daniel Fischer May 10 '13 at 15:00
  • @wilsonmichaelpatrick `offsetof` gives a `size_t`, which is unsigned. That would have to be the ordinary value. You'd get it per `(member_ptr - member_size) - (struct_ptr - struct_size)`. Such a scheme would involve a lot of fiddling with sizes and offsets, so it would not only be evil but also impractical, but could be done. – Daniel Fischer May 10 '13 at 15:06
  • @DanielFischer I'll stick to direct and void* casts then. (If void* didn't work, memcpy'ing of structures would probably be doomed!) –  May 10 '13 at 15:06
  • 1
    I think "suitably converted" means a cast of some sort. Can you think of any conversion that allows a pointer to an arbitrary struct to be converted to a pointer to its first member if the pointer refers to the last byte of the object? In your answer take into account that C99 explicitly allows the last member to be a variable length array. – JeremyP May 10 '13 at 15:06
  • @JeremyP Not a variable-length array, a flexible-array-member, you can always assume that that has size 0 for the computations. "Suitably converted" means conversions the standard says must work. Those are not many. Although, per 6.3.2.3 (7), one should make it work for all casts between object pointer types where the alignment requirements aren't violated. – Daniel Fischer May 10 '13 at 15:12
  • @DanielFischer: There's no guarantee that `&myB` and `(int32_t*)&myB` have the same bitwise representation, but I would expect that if sizeof(myB) is 12 and every pointer contains the numerical address of the last byte of the data item referred to thereby, then casting `&myB` to an `int32_t` would require subtracting 8 from the numerical address stored therein. – supercat May 10 '13 at 16:46
  • @supercat Yes, that's how it would work. In the example of the question, `sizeof myB` is 8 presumably (2 `int`s, one wrapped in a `struct A`), so the difference is 4. – Daniel Fischer May 10 '13 at 16:52