portable code

G

grid

Hi,
I recently came across a piece of code like this,
( & ( ( ( some struct * ) 0 ) -> element ) ) )

I had never seen this kind of code being used in any implementations so
far, but somehow remembered to have seen it sometime in clc, and that it
was for finding the offset of a member in a structure ( if I am not
horribly mistaken).

Now does this work ? Does this actually use the address 0x0, and when we
cast it to the particular structure, and try to obtain the address of an
element through this pointer, which turns out to be the offset of the
member because the base address is 0x0.

Many of you might argue about portability,but I have seen this code work
on multiple platforms.This means, it does work for quite a few different
platforms ( obviously with different implementations ), though it might
fail on some weird platform.Can we safely use this non-standard code in
places where we would have used a offsetof ?

Thanx,
~
 
?

=?iso-8859-1?q?Dag-Erling_Sm=F8rgrav?=

grid said:
I recently came across a piece of code like this,
( & ( ( ( some struct * ) 0 ) -> element ) ) )

I had never seen this kind of code being used in any implementations
so far, but somehow remembered to have seen it sometime in clc, and
that it was for finding the offset of a member in a structure ( if I
am not horribly mistaken).

Now does this work ? Does this actually use the address 0x0, and when
we cast it to the particular structure, and try to obtain the address
of an element through this pointer, which turns out to be the offset
of the member because the base address is 0x0.

No. The result of the expression you quote is a pointer. To get an
offset, you need to subtract (some struct *)0. The resulting value is
the difference between two pointers, so the actual value of the base
pointer does not matter:

#define offsetof(type, field) ((size_t)((char *)&((type *)0)->field - (char *)(type *)0))

You need the (char *) casts because &((type *)0)->field and (type *)0
are pointers to objects of incompatible types, so you can't subtract
one from the other directly.
Many of you might argue about portability,but I have seen this code
work on multiple platforms.This means, it does work for quite a few
different platforms ( obviously with different implementations ),
though it might fail on some weird platform.Can we safely use this
non-standard code in places where we would have used a offsetof ?

This is how offsetof is implemented on many platforms.

DES
 
A

Andrey Tarasevich

grid said:
...
I recently came across a piece of code like this,
( & ( ( ( some struct * ) 0 ) -> element ) ) )

I had never seen this kind of code being used in any implementations so
far, but somehow remembered to have seen it sometime in clc, and that it
was for finding the offset of a member in a structure ( if I am not
horribly mistaken).

This looks like [a portion of] the popular way to implement the
'offsetof' macro in the standard library.
Now does this work ?

In 'offsetof' it assumes that the resultant value, after conversion to
integral type, will represent the offset of the field in the structure.
Does this actually use the address 0x0, and when we
cast it to the particular structure, and try to obtain the address of an
element through this pointer, which turns out to be the offset of the
member because the base address is 0x0.
Exactly.

Many of you might argue about portability,but I have seen this code work
on multiple platforms.

As a part of standard library implementation, it is perfectly fine. The
implementation of the standard library is not required to be portable.
It is not even required to be implemented in C. It is just required to
work in accordance with its interface specification given in the
standard. Implementation details (like the above) are irrelevant.

If you explicitly put something like this into your own code, it becomes
a different story. It is indeed not portable, to say the least. The code
produces undefined behavior. But why would one want to do that anyway,
when you already have 'offsetof' in the standard library?
This means, it does work for quite a few different
platforms ( obviously with different implementations ), though it might
fail on some weird platform.

Yes. As it often turns out, the failing platform might not be as weird
as you expect.
Can we safely use this non-standard code in
places where we would have used a offsetof ?

"Safely" is a very stretchable word. Form the formal point of view of C
language - no, you can't. But, once again, why would anyone use it
instead of just using 'offsetof'?
 
W

william

grid said:
Hi,
I recently came across a piece of code like this,
( & ( ( ( some struct * ) 0 ) -> element ) ) )

I had never seen this kind of code being used in any implementations so
far, but somehow remembered to have seen it sometime in clc, and that it
was for finding the offset of a member in a structure ( if I am not
horribly mistaken).

Now does this work ? Does this actually use the address 0x0, and when we
cast it to the particular structure, and try to obtain the address of an
element through this pointer, which turns out to be the offset of the
member because the base address is 0x0.

Many of you might argue about portability,but I have seen this code work
on multiple platforms.This means, it does work for quite a few different
platforms ( obviously with different implementations ), though it might
fail on some weird platform.Can we safely use this non-standard code in
places where we would have used a offsetof ?

Thanx,
~



Define safely. As you point out it is possible for the code
to fail. On the other hand it is possible for an implementation
to have errors, or for a stray cosmic ray or two to mess up
an important register. So I guess the question is, is the danger
of using the construct low enough to to be outweighed by the
advantages [1].

The answer is, No. There are no advantages to using

( & ( ( ( some struct * ) 0 ) -> element ) ) )

rather than offsetof. If the above form works it will probably
be used by the implementation. If it does not work the implementation
will provide an offsetof that does work. Given that you are
going to wrap the ugly mess in a macro anyway (MY_OFFSETOF(foo))
you have gained percisely nothing [2].

- "William Hughes"


[1] This is the question that should be asked of any use
of a non portable construct. And very often the answer
is no, because there is no advantage [3] (often the question
is asked by people trying to outhink the implementation and
find efficiencies in intialization code that runs in
microseconds).

[2] It is possible that the implementation will provide a very
slow or broken offsetof. But in this case you have bigger
things to worry about than offsetof.

[3] There are cases where the general functions are not
adequate (e.g. cases where the malloc family of dynamic
memory allocation is not suitable). In this case a
specific and perhaps not fully portable solution may
be unavoidable. Still to first order: "If you have
to ask, the answer is no".
 
G

grid

[2] It is possible that the implementation will provide a very
slow or broken offsetof. But in this case you have bigger
things to worry about than offsetof.

I agree , but this does not stop implementors from using these
constructs for any gains (??) in performance . C is mostly popular
because of the power and flexibility it provides, though I am still
skeptical about the rationale behind this construct.

An offsetof macro could have done the trick , but the implementor chose
to use his own way, and as mentioned earlier , this code runs on many
popular UNIX platforms , so its not about an offsetof being broken or
slow for any particular platform.

~
 
W

william

grid said:
[2] It is possible that the implementation will provide a very
slow or broken offsetof. But in this case you have bigger
things to worry about than offsetof.

I agree , but this does not stop implementors from using these
constructs for any gains (??) in performance

a) (??) is right. offsetof is very unlikely to be
a performace bottleneck

b) implementors can (naturally) do whatever they like.
For an implementor, a non-portable trick that increases
performance is a GOOD THING.
C is mostly popular
because of the power and flexibility it provides, though I am still
skeptical about the rationale behind this construct.

The construct is clear enough. If the struct is at address zero, every
member will be at address offsetof(struct,member). The implementation
must know the offset of every member of every structure (how else
could the code be compiled?), but it may or may not recognize the
contruct as asking for this information. On the other hand
and implementation must recognize offsetof as asking for this
information.
An offsetof macro could have done the trick , but the implementor chose
to use his own way,

??? An implementor cannot use the offsetof macro/function,
The implementor must provide the offsetof macro/function.
and as mentioned earlier , this code runs on many
popular UNIX platforms ,

How and whether the construct works is a property of the
implementation.
Two implementations on the same machine, or the same implementation
with different environment or optimization settings
(or even the same implementationat different times
(this is undefined behaviour) ) may do different
things. The OS probably has little influence. That said, the
construct will probably work. So what. There is no upside
to using it.


- William Hughes
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top