portable code

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • grid

    #1

    portable code

    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,
    ~
  • Dag-Erling Smørgrav

    #2
    Re: portable code

    grid <prohit99@gmail .com> writes:[color=blue]
    > 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.[/color]

    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.
    [color=blue]
    > 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 ?[/color]

    This is how offsetof is implemented on many platforms.

    DES
    --
    Dag-Erling Smørgrav - des@des.no

    Comment

    • Andrey Tarasevich

      #3
      Re: portable code

      grid wrote:[color=blue]
      > ...
      > 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).[/color]

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

      In 'offsetof' it assumes that the resultant value, after conversion to
      integral type, will represent the offset of the field in the structure.
      [color=blue]
      > 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.[/color]

      Exactly.
      [color=blue]
      > Many of you might argue about portability,but I have seen this code work
      > on multiple platforms.[/color]

      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?
      [color=blue]
      > This means, it does work for quite a few different
      > platforms ( obviously with different implementations ), though it might
      > fail on some weird platform.[/color]

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

      "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

      Comment

      • william

        #4
        Re: portable code


        grid wrote:[color=blue]
        > 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[/color]
        so[color=blue]
        > far, but somehow remembered to have seen it sometime in clc, and that[/color]
        it[color=blue]
        > 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[/color]
        we[color=blue]
        > cast it to the particular structure, and try to obtain the address of[/color]
        an[color=blue]
        > element through this pointer, which turns out to be the offset of the[/color]
        [color=blue]
        > member because the base address is 0x0.
        >
        > Many of you might argue about portability,but I have seen this code[/color]
        work[color=blue]
        > on multiple platforms.This means, it does work for quite a few[/color]
        different[color=blue]
        > platforms ( obviously with different implementations ), though it[/color]
        might[color=blue]
        > fail on some weird platform.Can we safely use this non-standard code[/color]
        in[color=blue]
        > places where we would have used a offsetof ?
        >
        > Thanx,
        > ~[/color]



        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(fo o))
        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".

        Comment

        • grid

          #5
          Re: portable code

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

          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.

          ~

          Comment

          • william

            #6
            Re: portable code


            grid wrote:[color=blue][color=green]
            > > [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.[/color]
            >
            > I agree , but this does not stop implementors from using these
            > constructs for any gains (??) in performance[/color]

            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.
            [color=blue]
            > C is mostly popular
            > because of the power and flexibility it provides, though I am still
            > skeptical about the rationale behind this construct.
            >[/color]

            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.
            [color=blue]
            > An offsetof macro could have done the trick , but the implementor[/color]
            chose[color=blue]
            > to use his own way,[/color]

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

            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 implementationa t 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

            Comment

            Working...