Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Inheritance and offsetof

Reply
Thread Tools

Inheritance and offsetof

 
 
Marcel Müller
Guest
Posts: n/a
 
      09-21-2009
When I switch an existing project to gcc I get dozens of warnings
concerning offsetof. The code runs fine with and without gcc. Of course
this means nothing.

Example:


#include <stddef.h>

#define structoffsetof(type, base) ((int)(static_cast<base*>((type*)64))-64)

struct A
{ int m1;
int m2;
};

struct B : A
{ int m3;
};

int main()
{ A a;
a.m1 = offsetof(B, m3) - structoffsetof(B, A);
return 0;
}


test.cpp: In function `int main()':
test.cpp:16: warning: invalid access to non-static data member `A::m1'
of NULL object
test.cpp:16: warning: (perhaps the `offsetof' macro was used incorrectly)


Of course, it is because B is no longer a C style POD type because of
the inheritance. But even if the memory layout is up to the
implementation the offset of m3 should be stable.

I use this in a wrapper to a C library which takes struct A* as type and
requires relative offsets to custom components. I would prefer not to
use aggregation because A has many members and this would significantly
blow up the code.

Is it undefined behavior or is it only a warning?


Marcel
 
Reply With Quote
 
 
 
 
Francesco S. Carta
Guest
Posts: n/a
 
      09-21-2009
On 21 Set, 20:20, Marcel Müller <(E-Mail Removed)> wrote:
> When I switch an existing project to gcc I get dozens of warnings
> concerning offsetof. The code runs fine with and without gcc. Of course
> this means nothing.
>
> Example:
>
> #include <stddef.h>
>
> #define structoffsetof(type, base) ((int)(static_cast<base*>((type*)64))-64)
>
> struct A
> { int m1;
> * *int m2;
>
> };
>
> struct B : A
> { int m3;
>
> };
>
> int main()
> { A a;
> * *a.m1 = offsetof(B, m3) - structoffsetof(B, A);
> * *return 0;
>
> }
>
> test.cpp: In function `int main()':
> test.cpp:16: warning: invalid access to non-static data member `A::m1'
> of NULL object
> test.cpp:16: warning: (perhaps the `offsetof' macro was used incorrectly)
>
> Of course, it is because B is no longer a C style POD type because of
> the inheritance. But even if the memory layout is up to the
> implementation the offset of m3 should be stable.
>
> I use this in a wrapper to a C library which takes struct A* as type and
> requires relative offsets to custom components. I would prefer not to
> use aggregation because A has many members and this would significantly
> blow up the code.
>
> Is it undefined behavior or is it only a warning?


I have no answer to your questions but I have a question on my turn:
isn't there any better way to achieve the same result other than using
those macros?

I mean, if you want the offset of B over its base A, isn't enough to
call sizeof(A)?

Also, to get the offset of a member over the base address of an
object, isn't enough to compute the difference between those two
addresses?

I feel a bit confused.

Francesco
--
Francesco S. Carta, hobbyist
http://fscode.altervista.org
 
Reply With Quote
 
 
 
 
Francesco S. Carta
Guest
Posts: n/a
 
      09-21-2009
On 21 Set, 20:51, "Francesco S. Carta" <(E-Mail Removed)> wrote:
> On 21 Set, 20:20, Marcel Müller <(E-Mail Removed)> wrote:
>
>
>
> > When I switch an existing project to gcc I get dozens of warnings
> > concerning offsetof. The code runs fine with and without gcc. Of course
> > this means nothing.

>
> > Example:

>
> > #include <stddef.h>

>
> > #define structoffsetof(type, base) ((int)(static_cast<base*>((type*)64))-64)

>
> > struct A
> > { int m1;
> > * *int m2;

>
> > };

>
> > struct B : A
> > { int m3;

>
> > };

>
> > int main()
> > { A a;
> > * *a.m1 = offsetof(B, m3) - structoffsetof(B, A);
> > * *return 0;

>
> > }

>
> > test.cpp: In function `int main()':
> > test.cpp:16: warning: invalid access to non-static data member `A::m1'
> > of NULL object
> > test.cpp:16: warning: (perhaps the `offsetof' macro was used incorrectly)

>
> > Of course, it is because B is no longer a C style POD type because of
> > the inheritance. But even if the memory layout is up to the
> > implementation the offset of m3 should be stable.

>
> > I use this in a wrapper to a C library which takes struct A* as type and
> > requires relative offsets to custom components. I would prefer not to
> > use aggregation because A has many members and this would significantly
> > blow up the code.

>
> > Is it undefined behavior or is it only a warning?

>
> I have no answer to your questions but I have a question on my turn:
> isn't there any better way to achieve the same result other than using
> those macros?
>
> I mean, if you want the offset of B over its base A, isn't enough to
> call sizeof(A)?
>
> Also, to get the offset of a member over the base address of an
> object, isn't enough to compute the difference between those two
> addresses?
>
> I feel a bit confused.


Also, I think that either there is a problem in your structoffsetof
macro or in my understanding of your purposes (likely so) because it
equates to zero while I would have expected it to equate to "sizeof
(A)".

About the other macro, "offsetof(B, m3) == (size_t(&b.m3) - size_t
(&b))" on my system, hence I cannot see the need for that macro, which
does castings all over the place.

Where exactly did I lose myself?

Francesco
--
Francesco S. Carta, hobbyist
http://fscode.altervista.org
 
Reply With Quote
 
Marcel Müller
Guest
Posts: n/a
 
      09-21-2009
Francesco S. Carta wrote:
> Also, I think that either there is a problem in your structoffsetof
> macro or in my understanding of your purposes (likely so) because it
> equates to zero while I would have expected it to equate to "sizeof
> (A)".


Zero is correct for the most implementations, since A is the first base
class of B and both are non-polymorphic. But this macro does not raise
the warning. Calling offsetof is the problem.

> About the other macro, "offsetof(B, m3) == (size_t(&b.m3) - size_t
> (&b))" on my system,


The offset is needed relative to the start of A because A* is passed to
the C library.

> hence I cannot see the need for that macro, which
> does castings all over the place.


If you already have an instance of your type, you are right, but
otherwise you have to make your own pseudo-instance. And that is exactly
the way the macros offsetof and my structoffsetof work with all that casts.

Furthermore when dealing with an instance I would prefer to cast to
char*: (char*)&b.m3 - (char*)&(A&)b


Marcel
 
Reply With Quote
 
Francesco S. Carta
Guest
Posts: n/a
 
      09-21-2009
On 22 Set, 00:16, Marcel Müller <(E-Mail Removed)> wrote:
> Francesco S. Carta wrote:
> > Also, I think that either there is a problem in your structoffsetof
> > macro or in my understanding of your purposes (likely so) because it
> > equates to zero while I would have expected it to equate to "sizeof
> > (A)".

>
> Zero is correct for the most implementations, since A is the first base
> class of B and both are non-polymorphic. But this macro does not raise
> the warning. Calling offsetof is the problem.
>
> > About the other macro, "offsetof(B, m3) == (size_t(&b.m3) - size_t
> > (&b))" on my system,

>
> The offset is needed relative to the start of A because A* is passed to
> the C library.
>
> > hence I cannot see the need for that macro, which
> > does castings all over the place.

>
> If you already have an instance of your type, you are right, but
> otherwise you have to make your own pseudo-instance. And that is exactly
> the way the macros offsetof and my structoffsetof work with all that casts.
>
> Furthermore when dealing with an instance I would prefer to cast to
> char*: (char*)&b.m3 - (char*)&(A&)b


Thanks for your explanation, now it's clearer.

I still think you could avoid those macros, also you could avoid C-
style casts.

I'm just saying this because I've been told several times to never use
C-style casts, and also to avoid macros whenever possible - and for
such cases, I've been told to make macros all-caps.

Have you considered making some template functions to replace those
macros?

As I said, I have no answer for your specific issue, I'm just
bordering along, sorry.

Have good coding,
Francesco
--
Francesco S. Carta, hobbyist
http://fscode.altervista.org
 
Reply With Quote
 
Krice
Guest
Posts: n/a
 
      09-22-2009
On 22 syys, 01:16, Marcel Müller <(E-Mail Removed)> wrote:
> Calling offsetof is the problem.


It's the kind of problem that should be the end of career
for anyone who accepted that as valid source code.
 
Reply With Quote
 
Francesco S. Carta
Guest
Posts: n/a
 
      09-22-2009
On 22 Set, 08:23, Krice <(E-Mail Removed)> wrote:
> On 22 syys, 01:16, Marcel Müller <(E-Mail Removed)> wrote:
>
> > Calling offsetof is the problem.

>
> It's the kind of problem that should be the end of career
> for anyone who accepted that as valid source code.


Wow, is using offsetof _that_ bad?

I don't like that macro, fine, but can one be rightfully fired for
using it or for letting it pass during a code review?

Amazing. I must be either overvaluing peoples' jobs or undervaluing
coding rules, otherwise you should be voluntarily exaggerating - with
all the best purposes, of course.

Have good time,
Francesco
--
Francesco S. Carta, hobbyist
http://fscode.altervista.org
 
Reply With Quote
 
Marcel Müller
Guest
Posts: n/a
 
      09-22-2009
Francesco S. Carta wrote:
>> If you already have an instance of your type, you are right, but
>> otherwise you have to make your own pseudo-instance. And that is exactly
>> the way the macros offsetof and my structoffsetof work with all that casts.
>>
>> Furthermore when dealing with an instance I would prefer to cast to
>> char*: (char*)&b.m3 - (char*)&(A&)b

>
> Thanks for your explanation, now it's clearer.


I just saw a bug in the example, which may have caused confusion.
It should have been:
void foo(A*);
int main()
{ B b;
b.m1 = offsetof(B, m3) - structoffsetof(B, A);
foo(&b);
return 0;
}

> I still think you could avoid those macros, also you could avoid C-
> style casts.


I think there is no way of implementing things like offsetof without a
C-style cast.

> I'm just saying this because I've been told several times to never use
> C-style casts,


This works unless you have to deal with void* or something like offsetof.

> and also to avoid macros whenever possible - and for
> such cases, I've been told to make macros all-caps.
>
> Have you considered making some template functions to replace those
> macros?


Yes, just after my last post. Unfortunately while it is trivial to write
a template for structoffsetof I see no way to implement offsetof via a
template. It is because you cannot reasonably pass the element selector
as template argument without using lambda expressions. The latter would
require a very modern compiler because of the return type deduction.
Furthermore the compiler might no longer check that it is a compile time
constant.


> As I said, I have no answer for your specific issue, I'm just
> bordering along, sorry.


I think I will find a way to avoid this annoying warnings, again using
macros.
But I still wonder why offsetof should be invalid for inherited types.
The result of offsetof is not portable anyway because of alignment and
type size issues. But within a given plattform the result should be
stable as long as you do not deal with virtual base classes.


Marcel
 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      09-22-2009
On 22 sep, 00:39, "Francesco S. Carta" <(E-Mail Removed)> wrote:
> On 22 Set, 00:16, Marcel Müller <(E-Mail Removed)> wrote:
>
>
>
> > Francesco S. Carta wrote:
> > > Also, I think that either there is a problem in your structoffsetof
> > > macro or in my understanding of your purposes (likely so) because it
> > > equates to zero while I would have expected it to equate to "sizeof
> > > (A)".

>
> > Zero is correct for the most implementations, since A is the first base
> > class of B and both are non-polymorphic. But this macro does not raise
> > the warning. Calling offsetof is the problem.

>
> > > About the other macro, "offsetof(B, m3) == (size_t(&b.m3) - size_t
> > > (&b))" on my system,

>
> > The offset is needed relative to the start of A because A* is passed to
> > the C library.

>
> > > hence I cannot see the need for that macro, which
> > > does castings all over the place.

>
> > If you already have an instance of your type, you are right, but
> > otherwise you have to make your own pseudo-instance. And that is exactly
> > the way the macros offsetof and my structoffsetof work with all that casts.

>
> > Furthermore when dealing with an instance I would prefer to cast to
> > char*: (char*)&b.m3 - (char*)&(A&)b

>
> Thanks for your explanation, now it's clearer.
>
> I still think you could avoid those macros, also you could avoid C-
> style casts.
>
> I'm just saying this because I've been told several times to never use
> C-style casts, and also to avoid macros whenever possible - and for
> such cases, I've been told to make macros all-caps.
>
> Have you considered making some template functions to replace those
> macros?
>
> As I said, I have no answer for your specific issue, I'm just
> bordering along, sorry.


offsetof() only works with POD type. Since you have an inheritance, it
is no longer a POD type (the same would happen if you had defined
private data or defined a constructor).

The next standard defines a memory layout (standard layout) that will
makes this code conformant but it is not yet the case.

As it is, you could rewrite your code using composition or an union by
copying A members into B.

You will be able to cast a A* into a B* but you loose the type
checking (as in C).

--
Michael
 
Reply With Quote
 
Marcel Müller
Guest
Posts: n/a
 
      09-22-2009
Michael Doubez wrote:
> offsetof() only works with POD type. Since you have an inheritance, it
> is no longer a POD type (the same would happen if you had defined
> private data or defined a constructor).
>
> The next standard defines a memory layout (standard layout) that will
> makes this code conformant but it is not yet the case.


Thanks! That's what I want to know.

> As it is, you could rewrite your code using composition or an union by
> copying A members into B.


Of course. But the code now works and it will work in future. So I will
concentrate on to get rid of the warnings.

> You will be able to cast a A* into a B* but you loose the type
> checking (as in C).


Using composition there is a cleaner way.


Marcel
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
offsetof macro and non-POD structures. Solution. Pawel C Programming 8 10-19-2006 06:19 PM
Re: offsetof macro and non-POD structures. Solution. Christopher Benson-Manica C++ 2 10-18-2006 10:45 PM
More offsetof Tony Johansson C++ 3 12-18-2004 12:59 AM
offsetof Tony Johansson C++ 1 12-16-2004 12:32 AM
g++ "offsetof" problem Hiroki Horiuchi C++ 5 11-25-2003 05:01 PM



Advertisments