473,800 Members | 2,523 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

offsetof() macro

Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?

Thanks.

Simon

--
"Being a social outcast helps you stay concentrated on the really important
things, like thinking and hacking." - Eric S. Raymond

Nov 15 '05 #1
44 3756
Simon Morgan wrote:

Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


The offset of s_ptr->item could be taken as

((char *)&s_ptr->item) - ((char *)s_ptr)

Rather than having to create an actual "s_ptr" to use such a macro, it
can be shortcutted by simply using "((s *)constant)". By making the
"constant" zero, it also eliminates the need for the right-half of the
above equation.

There is nothing wrong with a NULL pointer, as long as you don't
dereference it. Taking it's address is fine.
Side question: what happens on platforms where NULL is not all-bits-
zero?

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer .h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th***** ********@gmail. com>
Nov 15 '05 #2
Simon Morgan <si***@16hz.net > wrote:
Hi,

Can somebody please help me grok the offsetof() macro?
I'll try.
I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


Preamble: note that the definition of the offsetof macro is highly
implementation specific. The one I'll use below is only one possible
solution, which happens to work on a variety of systems, while
miserably failing on others. An implementation may even call an
inbuilt function to calculate the offset of struct members by "black
magic" (read: compiler symbol table).

Ok, let's have a look at it:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

with s being the name of a structure type and m the name of a member
within that structure.

Now, if we want to get a grip at a complex C expression, we simply
read it inside out:

0 We take the integer constant 0,

(s *)0 cast to a pointer-to-object-of-type-s, thus pointing
at address 0; we now _pretend_ that at address 0 an
actual object of type s resides.

((s *)0)->m Now look at the member m of that object, which we do
not access, but instead

&(((s *)0)->m) take the address of. Since the address of the
structure object is 0, the address of m happens to
equal its offset in bytes.

(size_t)&(((s *)0)->m) Finally, we cast the result to a suitable
integral data type.

Note, however, that this specific implementation relies upon the fact,
that the underlying architecture allows for _meaningfully_ conversion
of an integral value into a memory address an vice versa.

HTH
Best regards
--
Irrwahn Grausewitz (ir*******@free net.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #3
Kenneth Brody wrote:
Simon Morgan wrote:

Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


The offset of s_ptr->item could be taken as

((char *)&s_ptr->item) - ((char *)s_ptr)

Rather than having to create an actual "s_ptr" to use such a macro, it
can be shortcutted by simply using "((s *)constant)". By making the
"constant" zero, it also eliminates the need for the right-half of the
above equation.

There is nothing wrong with a NULL pointer, as long as you don't
dereference it. Taking it's address is fine.
Side question: what happens on platforms where NULL is not all-bits-
zero?


Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer constant
with value 0 is the same as NULL.

I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to 0x1234.

If NULL is defined as something other than 0 (incl. non-integer values),
such a construct as:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
would not yield the correct value, hence why it is defined in <stddef.h>
along with NULL.

Note that I'm not an expert on the C standard unlike many people here, and I
could be giving totally wrong information.

BTW, I had to retrieve the "offsetof" of an array element, so here's a
complementary macro, only valid with a NULL value of 0, if what I said
above is correct.

#define array_offsetof( BASETYPE,ARRAY, INDEX) ((size_t) &((BASETYPE(*)A RRAY
0)[0]INDEX)

ex.:
int a[5][10][15];
/* offset of a[1][3] */
int offset = array_offsetof( int, [5][10][15], [1][3]);
--
Eric Laberge
Nov 15 '05 #4
Eric Laberge ha scritto:
Kenneth Brody wrote:

Simon Morgan wrote:
Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?


The offset of s_ptr->item could be taken as

((char *)&s_ptr->item) - ((char *)s_ptr)

Rather than having to create an actual "s_ptr" to use such a macro, it
can be shortcutted by simply using "((s *)constant)". By making the
"constant" zero, it also eliminates the need for the right-half of the
above equation.

There is nothing wrong with a NULL pointer, as long as you don't
dereference it. Taking it's address is fine.
Side question: what happens on platforms where NULL is not all-bits-
zero?

Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer constant
with value 0 is the same as NULL.

I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to 0x1234.


Are you sure? I've just compiled (gcc) and executed the code below, and
it prints '0x1234 (nil)'

#include <stdio.h>
#include <stdlib.h>
#undef NULL
#define NULL (void*)0x1234

int main()
{
int *pt1=NULL;
int *pt2=(int*)0;

printf("%p %p\n",pt1,pt2);

return 0;
}
--
Devaraja (Xdevaraja87^gm ail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #5
DevarajA <no@spam.com> wrote:
Eric Laberge ha scritto:
Kenneth Brody wrote: <snip>
Side question: what happens on platforms where NULL is not all-bits-
zero?
<snip> NULL is implementation-defined, but (6.3.2.3 Pointers) an integer constant
with value 0 is the same as NULL.

I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to 0x1234.
Are you sure? I've just compiled (gcc) and executed the code below, and
it prints '0x1234 (nil)'

#include <stdio.h>
#include <stdlib.h>
#undef NULL
#define NULL (void*)0x1234


Undefined behaviour, anything can happen.

Changing the definition of the NULL macro to one that yields an
arbitrarily chosen value on does not change the general behaviour
of the implementation itself.
However, nothing and nobody stops you from writing an implementation
which uses 0x1234 as the numerical value for each and any null
pointer. You just have to make sure it's different from any valid
object pointer (unlike above).
int main()
Better: int main(void)
{
int *pt1=NULL;
int *pt2=(int*)0;

printf("%p %p\n",pt1,pt2);
The %p format specifier expects an argument of type pointer-to-void.
return 0;
}


Regards.
--
Irrwahn Grausewitz (ir*******@free net.de)
welcome to clc : http://www.ungerhu.com/jxh/clc.welcome.txt
clc faq-list : http://www.faqs.org/faqs/C-faq/faq/
clc frequent answers: http://benpfaff.org/writings/clc.
Nov 15 '05 #6
DevarajA wrote:
Eric Laberge ha scritto:
<snip>
Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common
de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer
constant with value 0 is the same as NULL.
No, a constant expression in the *source* code used in a pointer context
is a null pointer constant. However, that has no bearing on how a null
pointer is represented in the program when it is run.
I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to
0x1234.


No, NULL has to be and integer constant expression evaluating to 0 or
such an expression cast to void*. However, if a null pointer is not all
bits 0 then the compiler will have to change it to whatever
representation is used for a null pointer when it compiles the code.

Equally, a float or double value of 0 does not have to be represented by
all bits 0.
Are you sure? I've just compiled (gcc) and executed the code below, and
it prints '0x1234 (nil)'

#include <stdio.h>
#include <stdlib.h>
#undef NULL
#define NULL (void*)0x1234
You are not the implementation, so you have not changed the
representation of a null pointer constant.
int main()
{
int *pt1=NULL;
int *pt2=(int*)0;

printf("%p %p\n",pt1,pt2);
%p is for void* pointers not other pointer types. They can be
represented differently.

return 0;
}


The reason the offsetof macro can make use of a null pointer in strange
ways is that it is part of the *implementation * and the implementer is
allowed to use whatever magic s/he wants as long as it produces the
correct result. User code can't portably use such tricks.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 15 '05 #7
Flash Gordon ha scritto:
DevarajA wrote:
Eric Laberge ha scritto:

<snip>
Both "NULL" and "offsetof" are defined in <stddef.h> (7.17 Common
de?nitions
<stddef.h>).

NULL is implementation-defined, but (6.3.2.3 Pointers) an integer
constant with value 0 is the same as NULL.

No, a constant expression in the *source* code used in a pointer context
is a null pointer constant. However, that has no bearing on how a null
pointer is represented in the program when it is run.
I suppose if, eg. the implementation decided that the value of NULL is
0x1234, then constant 0, when used as a pointer, would be equal to
0x1234.

No, NULL has to be and integer constant expression evaluating to 0 or
such an expression cast to void*. However, if a null pointer is not all
bits 0 then the compiler will have to change it to whatever
representation is used for a null pointer when it compiles the code.


So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),
but in the source code it must be represented as 0. And NULL macro just
expands into the null pointer constant, but I may also redefine it. Am I
right?

--
Devaraja (Xdevaraja87^gm ail^c0mX)
Linux Registerd User #338167
http://counter.li.org
Nov 15 '05 #8
On Thu, 08 Sep 2005 15:11:27 GMT, Simon Morgan <si***@16hz.net > wrote
in comp.lang.c:
Hi,

Can somebody please help me grok the offsetof() macro?

I've found an explanation on
http://www.embedded.com/shared/print...cleID=18312031
but I'm afraid it still doesn't make sense to me.

The sticking point seems to be:

((s *)0) takes the integer zero and casts it as a pointer to s.

To my untrained eye that would basically result in a null pointer. Does
this expression result in some special behaviour or am I missing
something?

Thanks.

Simon


The offsetof() macro is "special", as are many other things in the
standard C library and implementation. Just for example, the fopen()
function cannot itself be written in standard, portable C. It must
either interface with a lower-level API function provided by the
platform's operating system, or it must contain non-standard, hardware
specific code of its own to access a device that stores files.

Let's start with an example:

struct xyz { int x; int y; int z; };
The point is that once the compiler has processed the definition of a
structure type, it knows the offset of each of the members of the
structure. Once a human being (describes most programmers) has read
the structure definition, they know the offset of the first member,
'x', because it is at offset 0. They can guess or assume the offsets
of 'y' and 'z', but they can't really know.

There are times when it is quite useful to know the offset of a member
of a structure from the beginning of the structure. And the compiler
already has this information. So what we need is a way to write
source code that allows the compiler to provide this information to a
program when the program needs it.

Now, given our example definition, above, let's see how we can get the
offset of 'z' in a C program without using the offsetof() macro:

#include <stdio.h>
#include <stddef.h>

struct xyz { int x; int y; int z; };

int main(void)
{
struct xyz x_y_z = { 0 };
struct xyz *xyz_ptr = &x_y_z;
int *ip = &x_y_z.z;
ptrdiff_t diff = (char *)ip - (char *)xyz_ptr;
printf("%d\n", (int)diff);
return 0;
}

This is all perfectly valid, legal C code. You can cast any valid
pointer to any type of object to a pointer to char, and it will point
to the same address in memory as the lowest addressed byte of the
object. You can subtract two pointers of the same type, as long as
they both point within the same object. The result of the valid
subtraction between two pointers of the same type is the signed
integer type ptrdif_t, defined in <stddef.h>. Note that the
offsetof() macro is defined as yielding a type size_t, not ptrdif_t,
but that's a simple cast.

But to do this, we used an actual struct xyz object. What if we want
to do this without having one handy?

So let's try another version of the program which works with a pointer
to a struct xyz:

#include <stdio.h>
#include <stddef.h>

struct xyz { int x; int y; int z; };

size_t my_offsetof(str uct xyz *xyz_ptr)
{
size_t result =
(size_t)((char *)&xyz_ptr->z - (char *)xyz_ptr);
return result;
}

int main(void)
{
struct xyz x_y_z = { 0 };
printf("%d\n", (int)my_offseto f(&x_y_z));
return 0;
}

This produces the same result, which happens to be 8 on the particular
compiler that I am using. But note that even though the function
my_offsetof() does not define and create a struct xyz object, the
caller must have one handy to provide a pointer to the function.

If we want to do this without having a struct xyz object anywhere, we
could be tempted to change this line in main() from:

printf("%d\n", (int)my_offseto f(&x_y_z));

....to:

printf("%d\n", (int)my_offseto f(0));

....and on many compilers this will work just fine, and perhaps on some
few it will crash the program or produce unpredictable results. That
is because passing 0 or the macro NULL causes my_offsetof() to be
called with a null pointer. And the highlighted subexpression:

(size_t)((char *)&xyz_ptr->z - (char *)xyz_ptr);
^^^^^^^^^^

....dereference s that null pointer, although in actuality the compiler
does not need to dereference the pointer, since the value of
xyz_ptr->z is not used.

So on implementations where the compiler writer knows that his
compiler will not generate code to dereference the pointer, he can
define offsetof(s,m) like this:

#define offset(s, m) ((size_t)&((s *)0)->m)

....or something similar.

This code is not legal for you to write, but the implementer is not
constrained by the rules that apply to legal programs. The
implementer is allowed to bend or break the rules in standard library
functions and macros, so long as they deliver the proper results.

On the other hand, there are some compilers that do it differently. I
have seen definitions that look like this:

#define offset(s, m) __builtin_offse t__(s, m)

....that cause the compiler to look up the results in its symbol table
directly without going through the clumsy and technically undefined
operation on a null pointer.

The point is that there is a well-defined and perfectly legal sequence
that works properly on all compilers to get this information if there
is an object of the structure type available, but there is no legal,
defined method to get it without such an object. If there were, there
would have been no need for the language standard to require that the
implementation provides the macro.

So the point is, use the macro instead of trying to do the
calculations yourself. Even if you have an object of the type around,
the expression:

offsetof(struct xyz, z)

....is much more readable in your source code than:

(char *)&x_y_z->z - (char *)&x_y_z

....and the name of the macro makes the reason for its use
self-documenting.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 15 '05 #9
In article <jY************ *********@news4 .tin.it>,
DevarajA <no@spam.com> wrote:
So, tell me if I have understood... null pointer constant needs not to
have an all-0 internal representation (it is implementation-defined),
Right.
but in the source code it must be represented as 0.
The standard does not preclude other source-code representations , but 0
is the only portable one.
And NULL macro just
expands into the null pointer constant, but I may also redefine it. Am I
right?


It falls into the class of being reserved if any of the standard headers
are included.
--
Daylight is a trademark of OSRAM SYLVANIA INC.
Nov 15 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
6347
by: Hiroki Horiuchi | last post by:
Hello. I wrote a program, but g++ warns a.c:11: warning: invalid access to non-static data member `A::y' of NULL object a.c:11: warning: (perhaps the `offsetof' macro was used incorrectly) The program is like below. class A {
9
2970
by: Exits Funnel | last post by:
Consider this code which is a very trimmed down version of some I've inherited and am trying to port from windows to g++: //Begin test1.cpp class foo { int i; int j; }; class bar { bar (int foo::* dataMember) :offsetof (foo, *dataMember) //Call this Line (A)
6
2203
by: Arthur J. O'Dwyer | last post by:
As far as I know, C89/C90 did not contain the now-standard offsetof() macro. Did C89 mandate that structs had to have a consistent layout? For example, consider the typical layout of the following structure: struct weird { int x; /* sizeof(int)==4 here */
13
380
by: luke | last post by:
hi all, i have another question. I've read the FAQ regarding my former question (sizeof struct and union) and in question 2.14 it talks about offset macro. #define offsetof(type, mem) ((size_t) \ ((char *)&((type *)0)->mem - (char *)(type *)0)) Can anyone explain me how it works. 1)I can't understand what "0" casted to (type *) means
7
4539
by: Fred Zwarts | last post by:
Consider the following definition: typedef struct { int a; int b; } s; Now I have a function void f (int i) { ... }
8
5870
by: Pawel | last post by:
Hallo group members. //p1.cpp #include <stdio.h> #include <linux/stddef.h> struct Person { int m_age; char* m_name; };
11
2433
by: Kavya | last post by:
offsetof(T,m) (size_t)&(((T*)0)->m) Why do we always start from 0 in this macro to access the offset of structure or union. Does standard guarantees that structure and union reside at address 0? If yes, then what if I have two or more structures. How can they reside at same address?.
24
3500
by: Francine.Neary | last post by:
Just out of personal curiosity :) What do people use offsetof() for? I mean, I can understand why you'd want to be able to take the address of a member of a struct, but you can do that with just &(s.a) or similar. Why you'd care about the offset (which surely depends on how the compiler chooses to lay the struct out in memory), I don't really know. And if you did really care, won't offset(s,a) just be &(s.a) - &s ?
5
1902
by: mihirtr | last post by:
Hi, I have following structures and union typedef struct { int a; int b; char *c; }TEST_1;
0
9690
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9550
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10501
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10250
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9085
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6811
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5469
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5603
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2944
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.