endof

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Michael B Allen

    #1

    endof

    Is there a macro for determining the address of the end of an object? For
    example, if f is a pointer to an instance of the below struct, endof(f->a)
    would be equal to the address of member b.

    struct foo {
    int a[N];
    int b;
    };

    If not, is the following sufficient in all cases?

    #define endof(o) ((char *)(&(o)) + sizeof(o))

    Mike

  • Suman

    #2
    Re: endof



    Michael B Allen wrote:[color=blue]
    > Is there a macro for determining the address of the end of an object? For
    > example, if f is a pointer to an instance of the below struct, endof(f->a)
    > would be equal to the address of member b.
    >
    > struct foo {
    > int a[N];
    > int b;
    > };
    >
    > If not, is the following sufficient in all cases?
    >
    > #define endof(o) ((char *)(&(o)) + sizeof(o))
    >[/color]
    We have just had a pretty long discussion on offsetof() macro, that
    should
    serve you well.Look at the FAQ & search the group, please.

    Comment

    • Michael Mair

      #3
      Re: endof

      Michael B Allen wrote:[color=blue]
      > Is there a macro for determining the address of the end of an object? For
      > example, if f is a pointer to an instance of the below struct, endof(f->a)
      > would be equal to the address of member b.[/color]

      You mean the first address _after_ the end of an object.
      [color=blue]
      > struct foo {
      > int a[N];
      > int b;
      > };[/color]

      Note that there may be padding between structure members
      even in this case.
      The "relative address" of b within a struct foo can be found
      by using the offsetof macro from <stddef.h>
      [color=blue]
      > If not, is the following sufficient in all cases?
      >
      > #define endof(o) ((char *)(&(o)) + sizeof(o))[/color]

      Nope. Think of arrays passed (via pointer to their first element)
      to a function.
      It should work for scalar types and struct and union types.
      Depending on the intended use, I would consider casting the
      calculated address to void *.


      Cheers
      Michael
      --
      E-Mail: Mine is an /at/ gmx /dot/ de address.

      Comment

      • Christian Kandeler

        #4
        Re: endof

        Michael B Allen wrote:
        [color=blue]
        > Is there a macro for determining the address of the end of an object? For
        > example, if f is a pointer to an instance of the below struct, endof(f->a)
        > would be equal to the address of member b.[/color]

        I hope you are aware that the "end" of a and the beginning of b are not
        necessarily the same.
        And no, there is no macro for that in the standard library. And if there
        were, I'd wonder why.
        [color=blue]
        > struct foo {
        > int a[N];
        > int b;
        > };
        >
        > If not, is the following sufficient in all cases?
        >
        > #define endof(o) ((char *)(&(o)) + sizeof(o))[/color]

        If that is really what you want, then it's correct ;)
        What do you intend to use it for?


        Christian

        Comment

        • Lawrence Kirby

          #5
          Re: endof

          On Mon, 27 Jun 2005 09:07:21 +0200, Michael Mair wrote:

          ....
          [color=blue][color=green]
          >> If not, is the following sufficient in all cases?
          >>
          >> #define endof(o) ((char *)(&(o)) + sizeof(o))[/color]
          >
          > Nope. Think of arrays passed (via pointer to their first element)
          > to a function.[/color]

          The macro still works, but it gives you (one past) the end of the object
          you specify i.e. a pointer in that case.
          [color=blue]
          > It should work for scalar types and struct and union types.[/color]

          It works for arrays too, as long as you use on the actual array and not a
          pointer. For example with:
          [color=blue][color=green]
          >> struct foo {
          >> int a[N];
          >> int b;
          >> };[/color][/color]

          struct foo s;

          then

          endof(s.a);

          will give you the address of the character just after the end of s.a.

          Lawrence

          Comment

          • Michael Mair

            #6
            Re: endof

            Lawrence Kirby wrote:[color=blue]
            > On Mon, 27 Jun 2005 09:07:21 +0200, Michael Mair wrote:
            >
            > ...
            >
            >[color=green][color=darkred]
            >>>If not, is the following sufficient in all cases?
            >>>
            >>> #define endof(o) ((char *)(&(o)) + sizeof(o))[/color]
            >>
            >>Nope. Think of arrays passed (via pointer to their first element)
            >>to a function.[/color]
            >
            > The macro still works, but it gives you (one past) the end of the object
            > you specify i.e. a pointer in that case.[/color]

            Yep. I just wanted to warn about it.

            [color=blue][color=green]
            >>It should work for scalar types and struct and union types.[/color]
            >
            > It works for arrays too, as long as you use on the actual array and not a
            > pointer. For example with:
            >[color=green][color=darkred]
            >>> struct foo {
            >>> int a[N];
            >>> int b;
            >>> };[/color][/color]
            >
            > struct foo s;
            >
            > then
            >
            > endof(s.a);
            >
            > will give you the address of the character just after the end of s.a.[/color]

            Thanks, this was too sloppy on my part.

            Cheers
            Michael
            --
            E-Mail: Mine is an /at/ gmx /dot/ de address.

            Comment

            • Michael B Allen

              #7
              Re: endof

              On Mon, 27 Jun 2005 09:58:56 +0200, Christian Kandeler wrote:
              [color=blue][color=green]
              >> struct foo {
              >> int a[N];
              >> int b;
              >> };
              >>
              >> If not, is the following sufficient in all cases?
              >>
              >> #define endof(o) ((char *)(&(o)) + sizeof(o))[/color]
              >
              > If that is really what you want, then it's correct ;)
              > What do you intend to use it for?[/color]

              I'll give you two examples.

              1) I have a habit of using limit pointers where someone might normally
              pass a size. For example instead of using strncpy I prefer the following
              function instead:

              int
              str_copy(const unsigned char *src,
              const unsigned char *slim,
              unsigned char *dst,
              unsigned char *dlim,
              int n);

              The idea is that it's a little less error prone to assert 'src < slim'
              as opposed to 'n > 0' and then also have to adjust n by some appropriate
              amount. Now if all of your string processing functions are designed
              like this, they tend to cascade together resulting in overall smaller
              code. This is safer because slim never changes.

              So sometimes I find myself computing where the end of an object is. For
              example:

              struct foo {
              int i;
              char name[NAME_MAX];
              };

              str_copy(src, slim, f->name, endof(f->name));

              This case is a little too simple to illustrate its usefulness but I do
              a lot of complex decoding and encoding of formats and find techniques
              like this important.

              2) Another case is when I embed a bitset at the end of a struct to allow
              the number of bits to be variable like:

              struct fancy_array {
              ...
              void *blim; /* endof bitset */
              char bitset[1]; /* incomplete */
              }
              struct foo {
              struct fancy_array bar;
              char bar_bitset[MAX_BARS / 8];
              ...

              So bar_bitset just reserves space for the fancy_array's bitset. But to
              initialize this I need to pass the end of bar_bitset so we can set blim:

              fancy_array_ini t(&f->bar, endof(f->bar_bitset)) ;

              Mike

              Comment

              • Christian Kandeler

                #8
                Re: endof

                Michael B Allen wrote:
                [color=blue][color=green][color=darkred]
                >>> #define endof(o) ((char *)(&(o)) + sizeof(o))[/color]
                >>
                >> If that is really what you want, then it's correct ;)
                >> What do you intend to use it for?[/color]
                >
                > I'll give you two examples.
                >
                > 1) I have a habit of using limit pointers where someone might normally
                > pass a size.[/color]

                That's okay, then. As you may have noticed, some of us were afraid you'd use
                it to compute the offset of struct members.
                [color=blue]
                > For example instead of using strncpy I prefer the following
                > function instead:
                >
                > int
                > str_copy(const unsigned char *src,
                > const unsigned char *slim,
                > unsigned char *dst,
                > unsigned char *dlim,
                > int n);
                >
                > The idea is that it's a little less error prone to assert 'src < slim'
                > as opposed to 'n > 0' and then also have to adjust n by some appropriate
                > amount. Now if all of your string processing functions are designed
                > like this, they tend to cascade together resulting in overall smaller
                > code. This is safer because slim never changes.[/color]

                I don't see how that makes things safer. On the contrary, you are
                introducing redundancy (and a source for errors) by adding the additional
                constraint of (dlim - dst == slim - src). And on top of all that, you still
                pass n. I would stick with the canonical way.
                [color=blue]
                > So sometimes I find myself computing where the end of an object is. For
                > example:
                >
                > struct foo {
                > int i;
                > char name[NAME_MAX];
                > };
                >
                > str_copy(src, slim, f->name, endof(f->name));
                >
                > This case is a little too simple to illustrate its usefulness but I do
                > a lot of complex decoding and encoding of formats and find techniques
                > like this important.[/color]

                The technique of passing the same information with a higher number of
                arguments? ;)
                [color=blue]
                > 2) Another case is when I embed a bitset at the end of a struct to allow
                > the number of bits to be variable like:
                >
                > struct fancy_array {
                > ...
                > void *blim; /* endof bitset */
                > char bitset[1]; /* incomplete */[/color]

                Huh? Why is blim the end of bitset?
                [color=blue]
                > }
                > struct foo {
                > struct fancy_array bar;
                > char bar_bitset[MAX_BARS / 8];
                > ...
                >
                > So bar_bitset just reserves space for the fancy_array's bitset. But to
                > initialize this I need to pass the end of bar_bitset so we can set blim:
                >
                > fancy_array_ini t(&f->bar, endof(f->bar_bitset)) ;[/color]

                You completely lost me here... Either this makes no sense or I am stupid.


                Christian

                Comment

                • Michael Mair

                  #9
                  Re: endof

                  Christian Kandeler wrote:[color=blue]
                  > Michael B Allen wrote:
                  >
                  >[color=green][color=darkred]
                  >>>> #define endof(o) ((char *)(&(o)) + sizeof(o))
                  >>>
                  >>>If that is really what you want, then it's correct ;)
                  >>>What do you intend to use it for?[/color]
                  >>
                  >>I'll give you two examples.
                  >>
                  >>1) I have a habit of using limit pointers where someone might normally
                  >>pass a size.[/color]
                  >
                  > That's okay, then. As you may have noticed, some of us were afraid you'd use
                  > it to compute the offset of struct members.
                  >[color=green]
                  >>For example instead of using strncpy I prefer the following
                  >>function instead:
                  >>
                  >> int
                  >> str_copy(const unsigned char *src,
                  >> const unsigned char *slim,
                  >> unsigned char *dst,
                  >> unsigned char *dlim,
                  >> int n);
                  >>
                  >>The idea is that it's a little less error prone to assert 'src < slim'
                  >>as opposed to 'n > 0' and then also have to adjust n by some appropriate
                  >>amount. Now if all of your string processing functions are designed
                  >>like this, they tend to cascade together resulting in overall smaller
                  >>code. This is safer because slim never changes.[/color]
                  >
                  > I don't see how that makes things safer. On the contrary, you are
                  > introducing redundancy (and a source for errors) by adding the additional
                  > constraint of (dlim - dst == slim - src). And on top of all that, you still
                  > pass n. I would stick with the canonical way.[/color]

                  Yep, but n can now be easily larger than slim-src, or slim-src and/or
                  n can be larger than dlim-dst and you can easily implement the whole
                  thing safely.

                  [color=blue][color=green]
                  >>So sometimes I find myself computing where the end of an object is. For
                  >>example:
                  >>
                  >> struct foo {
                  >> int i;
                  >> char name[NAME_MAX];
                  >> };
                  >>
                  >> str_copy(src, slim, f->name, endof(f->name));
                  >>
                  >>This case is a little too simple to illustrate its usefulness but I do
                  >>a lot of complex decoding and encoding of formats and find techniques
                  >>like this important.[/color]
                  >
                  > The technique of passing the same information with a higher number of
                  > arguments? ;)[/color]

                  Nope. Think of copying something other than strings -- there you
                  need some way of finding out about maximum number of bytes to be
                  copied and maximum number of bytes the destination can hold.
                  At least with the above way of going about it, of course.

                  [color=blue][color=green]
                  >>2) Another case is when I embed a bitset at the end of a struct to allow
                  >>the number of bits to be variable like:
                  >>
                  >> struct fancy_array {
                  >> ...
                  >> void *blim; /* endof bitset */
                  >> char bitset[1]; /* incomplete */[/color]
                  >
                  > Huh? Why is blim the end of bitset?[/color]

                  It is not. But it is intended to _hold_ the end (see below)[color=blue]
                  >
                  >[color=green]
                  >> }
                  >> struct foo {
                  >> struct fancy_array bar;
                  >> char bar_bitset[MAX_BARS / 8];
                  >> ...
                  >>
                  >>So bar_bitset just reserves space for the fancy_array's bitset. But to
                  >>initialize this I need to pass the end of bar_bitset so we can set blim:
                  >>
                  >> fancy_array_ini t(&f->bar, endof(f->bar_bitset)) ;[/color]
                  >
                  > You completely lost me here... Either this makes no sense or I am stupid.[/color]

                  Neither. Think of it as a variant of the struct hack. Instead of
                  allocating the excess memory, you use automatic (or static)
                  struct variables. You can access everything by a pointer to struct
                  fancy_array, so fancy_array only has to know its "real" size or
                  its ends (stored in blim or passed explicitly to functions from
                  the outside.

                  Maybe the OP can clarify this further if I did not get all of it
                  (or are completely off the track).


                  Cheers
                  Michael
                  --
                  E-Mail: Mine is an /at/ gmx /dot/ de address.

                  Comment

                  • Michael B Allen

                    #10
                    Re: endof

                    On Wed, 29 Jun 2005 09:08:21 +0200, Michael Mair wrote:[color=blue][color=green][color=darkred]
                    >>>For example instead of using strncpy I prefer the following[/color][/color][/color]

                    Perhaps it is best if I just provide the function in question:

                    int
                    str_copy(const unsigned char *src,
                    const unsigned char *slim,
                    unsigned char *dst,
                    unsigned char *dlim,
                    int n)
                    {
                    unsigned char *start = dst;

                    if (dst == NULL || dst >= dlim) {
                    return 0;
                    }
                    if (src == NULL || src >= slim) {
                    *dst = '\0';
                    return 0;
                    }
                    while (n-- && *src) {
                    *dst++ = *src++;
                    if (src == slim || dst == dlim) {
                    dst = start;
                    break;
                    }
                    }
                    *dst = '\0';

                    return dst - start;
                    }
                    [color=blue][color=green]
                    >> I don't see how that makes things safer. On the contrary, you are
                    >> introducing redundancy (and a source for errors) by adding the additional
                    >> constraint of (dlim - dst == slim - src). And on top of all that, you still
                    >> pass n. I would stick with the canonical way.[/color]
                    >
                    > Yep, but n can now be easily larger than slim-src, or slim-src and/or
                    > n can be larger than dlim-dst and you can easily implement the whole
                    > thing safely.[/color]

                    Right. The lim pointers are just "fence post"s. When you decode or
                    encode something you usually know where the end of your buffer is and
                    that never changes (the limit pointer). Regardless of what hula-hoops
                    your code goes through the lim pointers should never change. This makes
                    the src < slim check very consistent and less prone to error because
                    you're not recomputing the sentinel all the time.

                    Admittedly that function might not be ideal to illustrate my point because
                    it does add the additional constaint of 'n'. Perhaps my alternative to
                    strlen is better:

                    int
                    str_length(cons t unsigned char *src, const unsigned char *slim)
                    {
                    const unsigned char *start = src;

                    if (src == NULL || src >= slim) {
                    return 0;
                    }
                    while (*src) {
                    src++;
                    if (src == slim) {
                    return 0;
                    }
                    }

                    return src - start;
                    }
                    [color=blue]
                    > Neither. Think of it as a variant of the struct hack. Instead of
                    > allocating the excess memory, you use automatic (or static)
                    > struct variables. You can access everything by a pointer to struct
                    > fancy_array, so fancy_array only has to know its "real" size or
                    > its ends (stored in blim or passed explicitly to functions from
                    > the outside.
                    >
                    > Maybe the OP can clarify this further if I did not get all of it
                    > (or are completely off the track).[/color]

                    That's exactly right. I didn't describe it very well but you get it.

                    Mike

                    Comment

                    Working...