Topic: offsetof and classes


Author: "Peter H bel" <ludvig@daimi.aau.dk>
Date: 1998/07/13
Raw View
> Christian Millour wrote in message <35A15350.6E5E9AE8@club-internet.fr>...
> According to FDIS 18.1.2 the use of offsetof is restricted
> to PODs.
> 1) Could someone please explain why ?
> 2) Are there compilers around for which it does not give the
> expected result ?
> 3) Is there an alternate portable way to convert between the
> address of a member data and the address of the containing
> instance (apart from lifting the member into a base class)

You might want to check out the discussion about creating
a portable layout-map for C++ objects in my paper

    ftp.//ftp.daimi.aau.dk/pub/stud/ludvig/aPersistentStoreForC++.ps.gz

This is the paper mentioned in Stroustrups "Design and Evolution of C++"

--peter



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/07/07
Raw View
Christian Millour <chris161@club-internet.fr> writes:

>Steve Clamage wrote:

>> In C++, class layout can vary considerably, and the offset of
>> a member is problematic. Examples:
>> 1. For a member of a virtual base class, the member offset
>> depends on whether the pointer you have points to the entire
>> object or a subobject. In other words, whether the result of
>> "offsetof" could successfully be applied to a pointer to a
>> derived class depends on how the offsetof was computed,
>> and the type of the complete object involved.

>Understood. However I'm only interested in converting
>a pointer to a member data into a pointer to the
>direct (sub)object that contains it. Once there one
>may always dynamic_cast one's way downwards.

Only if the classes are polymorphic. This is very dangerous
ground in any case. More below.

>> 2. A possible class layout might have some data members at
>> a negative offset from the object pointer, yet offsetof must
>> have type size_t, an unsigned type.

>I doubt it. Wouldn't such a layout rule out placement new,
>for instance ?

Implementations exist (Microsoft C++ for example) in which
the object pointer does not point to the start of the object.
It's extra work for the compiler, and has some pitfalls.
But MS C++ does not put data members at at negative offset.
I don't know of any that do. I merely point out that it is
allowed.

>> The only thing you don't get is the ability to go from
>> the address of a member to the address of the containing
>> class. If you really need that capability, put the data
>> members of interest into a POD-struct. You can make the
>> POD-struct a member or base class of the general C++ class.
>> You can then use offsetof on the POD-struct.

>A base class yes, but not a member :-).

Why not a member? Here's an example:

#include <stddef.h>
#include <assert.h>

struct Pod { // a POD-struct
    char* p, q;
    int   i, j;
    long  k, l;
};

class T {
public:
    Pod p;
    virtual void f(){}; // make it a non-POD class
};
T t;


// gets a pointer to 'i' member of a 'Pod'
void f(int* pi)
{
    Pod* pp = (Pod*)((char*)pi - offsetof(Pod, i));
    assert(pp == &t.p); // demonstrate that this works
}

int main()
{
    f(&t.p.i);
    return 0;
}

As with all such programs, there's no way to be sure that
function f really gets a pointer to an 'i' member of a 'Pod'.
It might get a pointer to an arbitrary integer, or to the
'j' member of a Pod, for example.

That's why you should prefer not to write such code in the
first place. For example, pass the address of the Pod or
of the T instead. I would argue that passing the address of
a member and computing the address of the containing struct
is bad program design. (But sometimes you inherit a poor
specification you can't change.)
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jkanze@otelo.ibmmail.com
Date: 1998/07/07
Raw View
In article <35A15350.6E5E9AE8@club-internet.fr>,
  Christian Millour <chris161@club-internet.fr> wrote:
>
> According to FDIS 18.1.2 the use of offsetof is restricted
> to PODs.
> 1) Could someone please explain why ?

Because it is really only there for C compatibility, and the committee
didn't want to impose restrictions on the implementation.

> 2) Are there compilers around for which it does not give the
> expected result ?

What expected results? The standard says that it is undefined behavior,
so you should have no expections:-).

Seriously: what are the expectations for static members? Member functions?
inherited members?  If you are only concerned with immediate data members,
I suspect that it will in fact work with compilers that use the traditional
trick involving address arithmetic on a dereferenced null pointer, but it
might fail if the compiler writer were intelligent enough to use a compiler
built-in to implement it.

> 3) Is there an alternate portable way to convert between the
> address of a member data and the address of the containing
> instance (apart from lifting the member into a base class)

Is it even guaranteed that this difference is a constant. (If the member
data is inherited from a virtual base class, it often won't be.)

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orientie objet --
              -- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/07/08
Raw View
Christian Millour wrote:
>
> Steve Clamage wrote:
>
> > 2. A possible class layout might have some data members at
> > a negative offset from the object pointer, yet offsetof must
> > have type size_t, an unsigned type.
>
> I doubt it. Wouldn't such a layout rule out placement new,
> for instance ?

In this case of sub-objects this is clearly possible. For
complete object I am convinced that it isn't.

I think that the address of any member must be >= to the
address of the complete object. I don't have a formal
proof I mind, but anyway it would be really strange to
try to break that.

Actually I am writing code relying on the some universal
notion of offsetof, which has to exist in every case
(static members excluded, of course). OTOH, I don't rely
on the offsetof macro itself.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jkanze@otelo.ibmmail.com
Date: 1998/07/08
Raw View
In article <35A2A513.4E1D@pratique.fr>,
  bonnardv@pratique.fr wrote:
> Christian Millour wrote:
> >
> > Steve Clamage wrote:
> >
> > > 2. A possible class layout might have some data members at
> > > a negative offset from the object pointer, yet offsetof must
> > > have type size_t, an unsigned type.
> >
> > I doubt it. Wouldn't such a layout rule out placement new,
> > for instance ?
>
> In this case of sub-objects this is clearly possible. For
> complete object I am convinced that it isn't.

Why?  On an Intel box, for example (or at least the older ones), there
could be definite advantages in making the complete object pointer point
to somewhere in the middle.  The necessary rules to make this work and
still conform to the special requirements of POD's are somewhat complex,
but the complexity is in the compiler, not the user code.

Placement new doesn't affect this in anyway.  The only difference between
placement new and normal new is the operator new function it calls.  Any
fix-ups needed by normal new would automatically be there for placement
new as well.

> I think that the address of any member must be >= to the
> address of the complete object. I don't have a formal
> proof I mind, but anyway it would be really strange to
> try to break that.

I can see nothing in the standard which requires this in any way.

> Actually I am writing code relying on the some universal
> notion of offsetof, which has to exist in every case
> (static members excluded, of course). OTOH, I don't rely
> on the offsetof macro itself.

Then your code is definitely not portable.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/07/08
Raw View
Steve Clamage wrote:
>> In C++, class layout can vary considerably, and the offset of
>> a member is problematic. Examples:
>> 1. For a member of a virtual base class, the member offset
>> depends on whether the pointer you have points to the entire
>> object or a subobject. In other words, whether the result of
>> "offsetof" could successfully be applied to a pointer to a
>> derived class depends on how the offsetof was computed,
>> and the type of the complete object involved.

Christian Millour wrote:
> Understood. However I'm only interested in converting
> a pointer to a member data into a pointer to the
> direct (sub)object that contains it. Once there, one
> may always dynamic_cast one's way downwards.

>> 2. A possible class layout might have some data members at
>> a negative offset from the object pointer, yet offsetof must
>> have type size_t, an unsigned type.
>
> I doubt it. Wouldn't such a layout rule out placement new,
> for instance ?

Uh, no.  HP-UX compilers, for example, place the base class
members of a derived object *after* the derived members, meaning
that a pointer to the derived object is different than a pointer
to the base [sub]object.  (Am I correct in saying that you must
specify the exact type of the operand to placement new?)

On the other hand, if you know that your object is less than
UINT_MAX/2 bytes long (which is typical), you can safely convert
the size_t result of offsetof() into a signed int offset:
    int i = offsetof(Foo, memb);
But I don't think that was the intended use for offsetof().

>> The only thing you don't get is the ability to go from
>> the address of a member to the address of the containing
>> class. If you really need that capability, put the data
>> members of interest into a POD-struct. You can make the
>> POD-struct a member or base class of the general C++ class.
>> You can then use offsetof on the POD-struct.
>
> A base class yes, but not a member :-).

Either way works:

    struct FooPod        // A POD class
    {
        int    i;
        int    j;
    };

    class Foo1:
        public FooPod    // Derived subclass
    {
        ...
    };

    class Foo2
    {
        FooPod   pod;    // POD member
        ...
    };

You can compute the offset of members 'i' and 'j' within struct
FooPod from either class Foo1 or Foo2.  Determining the offset
of the members within objects of non-POD types Foo1 and Foo2 is
still not possible, though.

Of course, there is nothing stopping you from attempting to
determine the offset of a member of a non-POD class; it's
just that offsetof() is not guaranteed to be capable of this.
For example:

    Foo  p;
    int  o = (const char *) &p.memb - (const char *) &p;

This will work as long as you're not messing with pointers to
derived types, and as long as 'memb' is not a reference type.
(The expression above is essentially the same as most
implementations of offsetof().)  But we must question the
propriety of this approach.


-- David R. Tribble, dtribble@technologist.com --
-- C++, the PL/1 of the 90s.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christian Millour <chris161@club-internet.fr>
Date: 1998/07/06
Raw View
According to FDIS 18.1.2 the use of offsetof is restricted
to PODs.
1) Could someone please explain why ?
2) Are there compilers around for which it does not give the
expected result ?
3) Is there an alternate portable way to convert between the
address of a member data and the address of the containing
instance (apart from lifting the member into a base class)

TIA.

--
Christian Millour                 mailto:chris161@club-internet.fr
Ing=E9nieur Conseil en Informatique     Tel/Fax:+33 [0]1 30 21 22 80
32 rue Edouard Charton         78000 Versailles             FRANCE


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/07/07
Raw View
Christian Millour <chris161@club-internet.fr> writes:

>According to FDIS 18.1.2 the use of offsetof is restricted
>to PODs.
>1) Could someone please explain why ?
>2) Are there compilers around for which it does not give the
>expected result ?
>3) Is there an alternate portable way to convert between the
>address of a member data and the address of the containing
>instance (apart from lifting the member into a base class)

In C, taking the offset of a struct member is quite sensible.
The data members are allocated in declaration order, with
nothing but padding between them.

In C++, class layout can vary considerably, and the offset of
a member is problematic. Examples:
1. For a member of a virtual base class, the member offset
depends on whether the pointer you have points to the entire
object or a subobject. In other words, whether the result of
"offsetof" could successfully be applied to a pointer to a
derived class depends on how the offsetof was computed,
and the type of the complete object involved.
2. A possible class layout might have some data members at
a negative offset from the object pointer, yet offsetof must
have type size_t, an unsigned type.

Since C++ has pointers to members, the offset is not as
important.  In addition, when you have an offset, you are
tempted to do arithmetic with it, which is liable to
produce nonsense for a general C++ class.

The only thing you don't get is the ability to go from
the address of a member to the address of the containing
class. If you really need that capability, put the data
members of interest into a POD-struct. You can make the
POD-struct a member or base class of the general C++ class.
You can then use offsetof on the POD-struct.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christian Millour <chris161@club-internet.fr>
Date: 1998/07/07
Raw View
Steve Clamage wrote:

> In C++, class layout can vary considerably, and the offset of
> a member is problematic. Examples:
> 1. For a member of a virtual base class, the member offset
> depends on whether the pointer you have points to the entire
> object or a subobject. In other words, whether the result of
> "offsetof" could successfully be applied to a pointer to a
> derived class depends on how the offsetof was computed,
> and the type of the complete object involved.

Understood. However I'm only interested in converting
a pointer to a member data into a pointer to the
direct (sub)object that contains it. Once there one
may always dynamic_cast one's way downwards.

> 2. A possible class layout might have some data members at
> a negative offset from the object pointer, yet offsetof must
> have type size_t, an unsigned type.

I doubt it. Wouldn't such a layout rule out placement new,
for instance ?

> The only thing you don't get is the ability to go from
> the address of a member to the address of the containing
> class. If you really need that capability, put the data
> members of interest into a POD-struct. You can make the
> POD-struct a member or base class of the general C++ class.
> You can then use offsetof on the POD-struct.

A base class yes, but not a member :-).

--
Christian Millour                 mailto:chris161@club-internet.fr
Ing=E9nieur Conseil en Informatique     Tel/Fax:+33 [0]1 30 21 22 80
32 rue Edouard Charton         78000 Versailles             FRANCE


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]