portable code

Discussion in 'C Programming' started by grid, Apr 1, 2005.

  1. grid

    grid Guest

    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,
    ~
     
    grid, Apr 1, 2005
    #1
    1. Advertising

  2. grid <> writes:
    > 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
    --
    Dag-Erling Smørgrav -
     
    =?iso-8859-1?q?Dag-Erling_Sm=F8rgrav?=, Apr 1, 2005
    #2
    1. Advertising

  3. grid wrote:
    > ...
    > 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'?

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Apr 1, 2005
    #3
  4. grid

    william Guest

    grid wrote:
    > 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".
     
    william, Apr 1, 2005
    #4
  5. grid

    grid Guest

    > [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.

    ~
     
    grid, Apr 2, 2005
    #5
  6. grid

    william Guest

    grid wrote:
    > > [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
     
    william, Apr 2, 2005
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eli Bendersky
    Replies:
    1
    Views:
    1,205
    Mike Treseler
    Mar 1, 2006
  2. Shin
    Replies:
    5
    Views:
    4,333
  3. The Saqe

    Looking for portable C++ code

    The Saqe, Sep 23, 2003, in forum: C++
    Replies:
    3
    Views:
    366
    Noah Roberts
    Sep 24, 2003
  4. Rolf Hemmerling
    Replies:
    3
    Views:
    780
    Roger Leigh
    Oct 31, 2003
  5. Replies:
    7
    Views:
    946
Loading...

Share This Page