offsetof macro and non-POD structures. Solution.

P

Pawel

Hallo group members.

//p1.cpp
#include <stdio.h>
#include <linux/stddef.h>

struct Person {
int m_age;
char* m_name;
};

struct Child: public Person {
unsigned short m_school_year;
};

int main()
{
printf ("offset to m_name: %d\n", offsetof(Child, m_name));
printf ("offset to m_length: %d\n", offsetof(Child, m_school_year));
}

As You know the program above compiles with a warning:
prompt$ g++ -g -O0 -o /tmp/p1 p1.cpp

p1.cpp: In function `int main()':
p1.cpp:16: warning: invalid access to non-static data member `Person::m_name' of NULL object
p1.cpp:16: warning: (perhaps the `offsetof' macro was used incorrectly)
p1.cpp:17: warning: invalid access to non-static data member `Child::m_school_year' of NULL object
p1.cpp:17: warning: (perhaps the `offsetof' macro was used incorrectly)


As I read in this newsgroup, the reason is casting 0 to address non-POD structure.
Indeed, the following code produces the same warning:

int main()
{
#define BASE 0x0
printf ( "m_name: %d\n", &((Child*)BASE)->m_school_year );
}

My question is: can I safely ignore this warning for structures of the complexity above?

Again, I found in this newsgroup that solution would be just to turn off this warning
with -Wno-invalid-offsetof flag.

Another solution is, if BASE != 0, then warning is not produced, so that would be the solution.

offsetof macro would look like following:
#define OFFSETOF_BASE 0x1
#define Offsetof(TYPE, MEMBER) \
(size_t)((unsigned char*)(&(((TYPE*)OFFSETOF_BASE)->MEMBER)) - (unsigned char*)(TYPE*)OFFSETOF_BASE)

Regards,
Pawel
 
R

Richard Bos

Pawel said:
Hallo group members.

//p1.cpp
#include <stdio.h>
#include <linux/stddef.h>

struct Person {
int m_age;
char* m_name;
};

struct Child: public Person {

This is not C. (And it's not C++, either, because then both headers
above would be wrong.)
unsigned short m_school_year;
};

int main()
{
printf ("offset to m_name: %d\n", offsetof(Child, m_name));

This is wrong; there is no Child, and struct Child has no member called
m_name in C. It may in C++, but for information on that you need to ask
in comp.lang.c++, not here.
printf ("offset to m_length: %d\n", offsetof(Child, m_school_year));

If corrected to read struct Child, this is almost correct.

Both printf() statements also print a size_t, which is unsigned and of
unknown width, using %d. That, too, is wrong. You should either cast
offsetof() to unsigned long and use %lu, or use a C99 implemetation and
%zu. This is not likely to be your underlying problem, but it's still
wrong.
}

As You know the program above compiles with a warning:

Do I? As you _should_ know, different compilers issue different warnings
for different problems.
prompt$ g++ -g -O0 -o /tmp/p1 p1.cpp

p1.cpp: In function `int main()':
p1.cpp:16: warning: invalid access to non-static data member `Person::m_name' of NULL object
p1.cpp:16: warning: (perhaps the `offsetof' macro was used incorrectly)
p1.cpp:17: warning: invalid access to non-static data member `Child::m_school_year' of NULL object
p1.cpp:17: warning: (perhaps the `offsetof' macro was used incorrectly)

Neither of those make complete sense in a C context, but the latter a
bit more than the former.
In any case, with the two corrections I mentioned above, your _last_
call of offsetof() would be correct C, and should, for a non-broken
implementation, not give warnings. In theory an implementation is
allowed to print whatever warnings it likes, but as a QoI issue, it
ought not to for this case.
As I read in this newsgroup, the reason is casting 0 to address non-POD structure.

What is an "address non-POD structure"?

In any case, the offsetof() that got delivered with your implementation
in <stddef.h> (_not_ <linux/stddef.h>!) should be usable without
warnings. If not, that is IMO a bug in the implementation, and you
should complain to your supplier.
Indeed, the following code produces the same warning:

int main()
{
#define BASE 0x0
printf ( "m_name: %d\n", &((Child*)BASE)->m_school_year );
}

Why not simply use NULL?
My question is: can I safely ignore this warning for structures of the complexity above?

No. The warning means that _you_ can't safely do this, on this
implementation. If you get that same warning for the normal, ISO C
offsetof() macro, the warning means that your implementation is broken.
Again, I found in this newsgroup that solution would be just to turn off this warning
with -Wno-invalid-offsetof flag.

That's as may be, but that is an implementation-dependent solution, and
I could not possibly comment on its value.
Another solution is, if BASE != 0, then warning is not produced, so that would be the solution.

offsetof macro would look like following:
#define OFFSETOF_BASE 0x1
#define Offsetof(TYPE, MEMBER) \
(size_t)((unsigned char*)(&(((TYPE*)OFFSETOF_BASE)->MEMBER)) - (unsigned char*)(TYPE*)OFFSETOF_BASE)

That, however, replaces a warning with definite undefined behaviour, and
is therefore a cure worse than the problem. Don't do this at all; you
may be inviting your program to crash at the most inopportune moment.
Instead, make sure that you get a full, correct implementation; in
particular, make sure that your headers and your compiler fit together,
and that you use the correct headers, not after-market ones.

Richard
 
M

Martin Ambuhl

Pawel said:
Hallo group members.

//p1.cpp
^^^^
Probably not a C translation unit. If not, it is not topical in comp.lang.c
#include <stdio.h>
#include <linux/stddef.h>
^^^^^^^^^^^^^^^^
implementation specific header, so not topical in comp.lang.c. If there
a reason not to use the topical said:
struct Person {
int m_age;
char* m_name;
};

struct Child: public Person {
^^^^^^^^^^^^^
':' syntax error
'public' undefined identifier
*Certainly* not topical in comp.lang.c. Are you perhaps confused,
thinking that the different programming language C++ should be of the
slightest interest in comp.lang.c?
[remaining silliness removed]
 
D

Default User

Richard said:
This is not C. (And it's not C++, either, because then both headers
above would be wrong.)


While the C-headers such as <stdio.h> are deprecated in C++, they are
standard. In fact, I suspect that they will persist through many more
revisions of the C++ standard.




Brian
 
C

Christopher Benson-Manica

(crossposted to comp.lang.c++, f'ups set)
While the C-headers such as <stdio.h> are deprecated in C++, they are
standard. In fact, I suspect that they will persist through many more
revisions of the C++ standard.

I gather that the rest of the headers held over from C (<string.h>,
<stdlib.h>, etc.) are also standard?
 
R

Richard Bos

Default User said:
While the C-headers such as <stdio.h> are deprecated in C++, they are
standard. In fact, I suspect that they will persist through many more
revisions of the C++ standard.

I was under the impression that they're supposed to be called <cstdio.h>
or something like that?

Richard
 
K

Keith Thompson

I was under the impression that they're supposed to be called <cstdio.h>
or something like that?

I don't know, but I'm sure the folks in comp.lang.c++ do.
 
D

Default User

Richard said:
I was under the impression that they're supposed to be called
<cstdio.h> or something like that?

See my message elsethread about this. Otherwise, drop me email or we
could continue this on clc++.




Brian
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top