pointer-in-array test

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dik T. Winter

    #16
    Re: pointer-in-array test

    In article <1133145.9pkQ6i reiI@holzmayer. ifr.rt> holzmayer.bernh ard@deadspam.co m writes:
    ....[color=blue]
    > What about this solution:
    > int ptrInArrSafe(T *p,T *a,int max)
    > /* check whether p points to an element of a[max] */
    > {
    > long px = (long)p;
    > long ax = (long)a;
    > if (px<ax) return 0; /*out*/
    > if (px> (long)&a[max-1]) return 0; /* out */
    > if ( (px-ax) % sizeof(T)) return 0; /* not at element start*/
    > return 1; /* in and on element start */
    > }
    >
    > compiles, links, runs without problems with my gcc.
    > And, as far as I remember, it's legal, to compare pointers after
    > conversion to long.[/color]

    But the result is implementation defined. I know of at least one
    system where it will fail to give the correct answer, then T is char.
    For instance:
    (long)(a + 7) > (long)(a + 8)
    when a is an array of type char.
    --
    dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
    home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

    Comment

    • Eric Sosman

      #17
      Re: pointer-in-array test

      Ike Naar wrote:[color=blue]
      > [...]
      > A more efficient algorithm is
      >
      > int ptrInArrUnsafe( T *p,T *a,int max)
      > /* check whether p points to an element of a[max] */
      > {
      > int j=p-a; /* possibly undefined */
      > return 0<=j && j<max && a+j==p;
      > }
      >
      > If p points to an element of a[max], j will be a valid index and
      > the return expression will evaluate to true.[/color]

      Agree.
      [color=blue]
      > If p does not point to an element of a[max], the pointer subtraction may
      > invoke undefined behaviour; garbage will be stored in j, and at least one
      > of the conjuncts of the return expression will evaluate to false.[/color]

      Disagree. Everything seems correct up to the semicolon,
      but after that things fall apart:

      - First, it is not necessarily the case that garbage will
      be stored in j. "Undefined behavior" is "undefined, "
      and does not necessarily result in storing anything at
      all anywhere at all.

      - Second, even if something does get stored into j, it's
      not certain that the "something" will be recognizable
      as "garbage." For example, the value zero might be
      stored into j, just as if you had called

      ptrInArrUnsafe( &array[0], array, 1)

      - ... and if this (or something like it) happens, the
      return expression will evaluate true, not false.
      [color=blue]
      > Apart from storing garbage in j, the pointer subtraction could, in theory,
      > crash the system, re-format the floppy disk or wake up nasal daemons,
      > but this has not happened so far on any platform with any compiler
      > (tried several).[/color]

      Personally, I've never seen demons fly from my nose (they're
      awfully fast, and are usually out of sight before I notice them).
      But one need not invoke exotic architectures to get weird behavior
      out of violating the rules of pointer subtraction. For example,
      consider a "plain vanilla" system with nice linear addressing,
      where pointers are just unadorned numeric addresses. Now try
      this on for size:

      typedef char[8] T;
      T array[5];
      printf ("%d\n", ptrInArrUnsafe( &array[0][1], array, 5));

      It is quite likely (not certain, of course: undefined behavior
      is undefined) that j will compute as zero inside the function,
      leading the function to conclude that the pointer is valid.
      The conclusion is utterly wrong, of course: the pointer aims
      not at the start of a T object, but one byte past the start
      of the first T object in the array.
      [color=blue]
      > My question is, do you experts in this group see any real problem with
      > the second algorithm?[/color]

      Yes, as explained above.
      [color=blue]
      > Alternatively, would there be a faster algorithm
      > than the first one, that does not invoke undefined behaviour?[/color]

      I cannot think of one. As CBF suggests, you should (a)
      re-examine whether such a test is required, and if it is
      you should (b) isolate the test to a system-dependent source
      file, not intended to be portable.

      --
      Eric.Sosman@sun .com

      Comment

      • CBFalconer

        #18
        Re: pointer-in-array test

        Ike Naar wrote:[color=blue]
        >[/color]
        .... snip ...[color=blue]
        >
        > But apart from stylistic differences, I see no reason why your
        > solution would be any faster or slower than mine.
        > Both algorithms perform a linear search on the array.[/color]

        I did say "possibly". It would depend on the optimization
        capabilities of the compiler.

        --
        Chuck F (cbfalconer@yah oo.com) (cbfalconer@wor ldnet.att.net)
        Available for consulting/temporary embedded and systems.
        <http://cbfalconer.home .att.net> USE worldnet address!


        Comment

        • Ike Naar

          #19
          Re: pointer-in-array test

          Hi Eric,

          Eric Sosman <Eric.Sosman@su n.com> wrote:
          : Ike Naar wrote:
          :> int ptrInArrUnsafe( T *p,T *a,int max)
          :> /* check whether p points to an element of a[max] */
          :> {
          :> int j=p-a; /* possibly undefined */
          :> return 0<=j && j<max && a+j==p;
          :> }
          :> [...]
          :> If p does not point to an element of a[max], the pointer subtraction may
          :> invoke undefined behaviour; garbage will be stored in j, and at least one
          :> of the conjuncts of the return expression will evaluate to false.
          : Disagree. Everything seems correct up to the semicolon,
          : but after that things fall apart:
          : - First, it is not necessarily the case that garbage will
          : be stored in j. "Undefined behavior" is "undefined, "
          : and does not necessarily result in storing anything at
          : all anywhere at all.

          Of course the implementation is free to do anything it wants after
          undefined behaviour, but let's pretend that the damage is limited
          to whatever is stored in j. If nothing is stored in j, fine. Perhaps
          j retains its old value (whatever that was).

          : - Second, even if something does get stored into j, it's
          : not certain that the "something" will be recognizable
          : as "garbage."

          It seems that our notions of "garbage" differ.
          My garbage can have any value.

          : For example, the value zero might be
          : stored into j, just as if you had called
          : ptrInArrUnsafe( &array[0], array, 1)
          : - ... and if this (or something like it) happens, the
          : return expression will evaluate true, not false.

          If 0<=j<max, the last conjuct (a+j==p) has to be false, due to the
          initial assumption that p was not pointing to an element of a .

          Conversely, if the return expression evaluates true there would
          have been no undefined behaviour, since in that case there exists
          an index j such that 0<=j<max and &a[j]==p (that's what the return
          expression implies), i.e. p points to an element of a, and
          the pointer subtraction (p-a) would have been OK.

          :> [...]
          : But one need not invoke exotic architectures to get weird behavior
          : out of violating the rules of pointer subtraction. For example,
          : consider a "plain vanilla" system with nice linear addressing,
          : where pointers are just unadorned numeric addresses. Now try
          : this on for size:

          : typedef char[8] T;

          <nitpicking -- this is C.L.C. after all, isn't it?>
          typedef char T[8];
          </nitpicking>

          : T array[5];
          : printf ("%d\n", ptrInArrUnsafe( &array[0][1], array, 5));

          This is an extra complication that does not apply to the original problem
          where p is supposed to have type T* . &array[0][1] is not a T* .

          : It is quite likely (not certain, of course: undefined behavior
          : is undefined) that j will compute as zero inside the function,
          : leading the function to conclude that the pointer is valid.
          : The conclusion is utterly wrong, of course: the pointer aims
          : not at the start of a T object, but one byte past the start
          : of the first T object in the array.

          : --
          : Eric.Sosman@sun .com

          --
          mail to ike at iae dot nl

          Comment

          • Eric Sosman

            #20
            Re: pointer-in-array test

            Ike Naar wrote:[color=blue]
            >
            > Hi Eric,
            >
            > Eric Sosman <Eric.Sosman@su n.com> wrote:
            > : Ike Naar wrote:
            > :> int ptrInArrUnsafe( T *p,T *a,int max)
            > :> /* check whether p points to an element of a[max] */
            > :> {
            > :> int j=p-a; /* possibly undefined */
            > :> return 0<=j && j<max && a+j==p;
            > :> }
            > :>
            > : - ... and if this (or something like it) happens, the
            > : return expression will evaluate true, not false.
            >
            > If 0<=j<max, the last conjuct (a+j==p) has to be false, due to the
            > initial assumption that p was not pointing to an element of a .[/color]

            Ah, yes. Sorry about that; my reading comprehension
            diminishes rapidly once the U.B. alarm bells start ringing.
            [color=blue]
            > Conversely, if the return expression evaluates true there would
            > have been no undefined behaviour, since in that case there exists
            > an index j such that 0<=j<max and &a[j]==p (that's what the return
            > expression implies), i.e. p points to an element of a, and
            > the pointer subtraction (p-a) would have been OK.
            >
            > :> [...]
            > : But one need not invoke exotic architectures to get weird behavior
            > : out of violating the rules of pointer subtraction. For example,
            > : consider a "plain vanilla" system with nice linear addressing,
            > : where pointers are just unadorned numeric addresses. Now try
            > : this on for size:
            >
            > : typedef char[8] T;
            >
            > <nitpicking -- this is C.L.C. after all, isn't it?>
            > typedef char T[8];
            > </nitpicking>[/color]

            Right again, and I've clearly become Java-polluted.
            [color=blue]
            > : T array[5];
            > : printf ("%d\n", ptrInArrUnsafe( &array[0][1], array, 5));
            >
            > This is an extra complication that does not apply to the original problem
            > where p is supposed to have type T* . &array[0][1] is not a T* .[/color]

            Right again, but this time it was just an editing error.
            I'd started with

            (T*)((char*)arr ay + 1)

            .... and lost the cast when simplifying. The first argument
            ought to have been

            (T*)&array[0][1]

            Now, there are lots of opportunities for things to go wrong
            with this. The conversion to T* might garble the address --
            but in the example I was assuming a "plain vanilla" machine
            on which that wouldn't happen. The pointer subtraction in
            the function is still likely to yield zero by (more or less)
            subtracting the two addresses to get 1 and then right-shifting
            by three bits. It is, I guess, unlikely that a "plain vanilla"
            machine would decide that (T*)&array[0][1] and array[0]+0 are
            equal -- no guarantees, of course, but unlikely.

            All in all, I'd say my attempt to express objections has
            turned into an awful hash. Nonetheless ("Don't confuse me
            with the facts; my mind is made up!") I'll still second CBF's
            recommendation that shenanigans of this sort should be avoided,
            or at the very least isolated.

            --
            Eric.Sosman@sun .com

            Comment

            • Christian Bau

              #21
              Re: pointer-in-array test

              In article <1133145.9pkQ6i reiI@holzmayer. ifr.rt>,
              Bernhard Holzmayer <holzmayer.bern hard@deadspam.c om> wrote:
              [color=blue]
              > Sorry,
              > pardon me for not checking my code intensively enough.
              > I just checked with a 'gcc -pedantic' which didn't throw an error :(
              >
              > What about this solution:
              > int ptrInArrSafe(T *p,T *a,int max)
              > /* check whether p points to an element of a[max] */
              > {
              > long px = (long)p;
              > long ax = (long)a;
              > if (px<ax) return 0; /*out*/
              > if (px> (long)&a[max-1]) return 0; /* out */
              > if ( (px-ax) % sizeof(T)) return 0; /* not at element start*/
              > return 1; /* in and on element start */
              > }
              >
              > compiles, links, runs without problems with my gcc.
              > And, as far as I remember, it's legal, to compare pointers after
              > conversion to long.[/color]

              It just isn't guaranteed to produce any meaningful result.

              Comment

              • Keith Thompson

                #22
                Re: pointer-in-array test

                Bernhard Holzmayer <holzmayer.bern hard@deadspam.c om> writes:[color=blue]
                > Keith Thompson wrote:
                >[color=green]
                > > Barry Schwarz <schwarzb@deloz .net> writes:
                > > [...][color=darkred]
                > >> If your system supports the optional intptr_t type, you can
                > >> convert p, a, and a+1 to integers and determine the correct
                > >> answer without fear of undefined behavior.[/color]
                > >
                > > The only guarantee for intptr_t is that you can convert a void* to
                > > intptr_t and back to void*, and the result will compare equal to
                > > the
                > > original void*. It's not clear (to me) that relational operators
                > > are sufficiently well-defined to allow reliably checking whether a
                > > pointer points within an array.
                > >
                > > Suppose a char* pointer consists of a word pointer with a byte
                > > offset in the high-order bits, and that pointer-to-integer[/color]
                > pointer-to-integer is not enough.
                > IMHO you have to use pointer-to-long which must be well-defined
                > according to the standard, which means, that a long is big enough
                > to hold a pointer on that system. An integer might be too short.[/color]

                By "word pointer", I meant a pointer to a word. There's no necessary
                relationship between a integer and a pointer-to-integer -- and the
                term "integer" includes all integer types, not just int.

                The concrete example I have in mind is Cray vector systems. A machine
                word is 64 bits; there are no instructions that operate directly on
                8-bit bytes. Nevertheless, the C implementation has CHAR_BIT==8, so
                it needs to have a way to represent pointers to 8-bit bytes.

                An int* (int is 64 bits) is simply a word pointer with the obvious
                representation. If you take an int*, treat it as a 64-bit integer,
                increment it, and convert it back to int*, the resulting pointer will
                point to the 64-bit word immediately following the original one.

                A char* consists of a word pointer, pointing to the 64-bit word
                containing the byte, with a 3-bit byte offset (value 0..7) stored in
                the high-order 3 bits (which would otherwise be zero, since no such
                system has a large enough address space to need them).

                --
                Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                Schroedinger does Shakespeare: "To be *and* not to be"

                Comment

                • Bernhard Holzmayer

                  #23
                  Re: pointer-in-array test

                  Dik T. Winter wrote:
                  [color=blue]
                  > In article <1133145.9pkQ6i reiI@holzmayer. ifr.rt>
                  > holzmayer.bernh ard@deadspam.co m writes: ...[color=green]
                  > > What about this solution:
                  > > int ptrInArrSafe(T *p,T *a,int max)
                  > > /* check whether p points to an element of a[max] */
                  > > {
                  > > long px = (long)p;
                  > > long ax = (long)a;
                  > > if (px<ax) return 0; /*out*/
                  > > if (px> (long)&a[max-1]) return 0; /* out */
                  > > if ( (px-ax) % sizeof(T)) return 0; /* not at element
                  > > start*/
                  > > return 1; /* in and on element start */
                  > > }
                  > >
                  > > compiles, links, runs without problems with my gcc.
                  > > And, as far as I remember, it's legal, to compare pointers
                  > > after conversion to long.[/color]
                  >
                  > But the result is implementation defined. I know of at least one
                  > system where it will fail to give the correct answer, then T is
                  > char. For instance:
                  > (long)(a + 7) > (long)(a + 8)
                  > when a is an array of type char.[/color]

                  That's not the same.
                  Would you please try the following:
                  (long)(&a[7]) < (long)(&a[8])

                  this should give the correct result.

                  Reason for your strange behaviour is possibly the implicite type
                  cast, which converts a before adding.
                  Instead, the later version increments a as a pointer and then
                  converts it.

                  Bernhard

                  Comment

                  • Bernhard Holzmayer

                    #24
                    Re: pointer-in-array test

                    Christian Bau wrote:
                    [color=blue]
                    > In article <1133145.9pkQ6i reiI@holzmayer. ifr.rt>,
                    > Bernhard Holzmayer <holzmayer.bern hard@deadspam.c om> wrote:
                    >[color=green]
                    >> Sorry,
                    >> pardon me for not checking my code intensively enough.
                    >> I just checked with a 'gcc -pedantic' which didn't throw an error
                    >> :(
                    >>
                    >> What about this solution:
                    >> int ptrInArrSafe(T *p,T *a,int max)
                    >> /* check whether p points to an element of a[max] */
                    >> {
                    >> long px = (long)p;
                    >> long ax = (long)a;
                    >> if (px<ax) return 0; /*out*/
                    >> if (px> (long)&a[max-1]) return 0; /* out */
                    >> if ( (px-ax) % sizeof(T)) return 0; /* not at element
                    >> start*/
                    >> return 1; /* in and on element start */
                    >> }
                    >>
                    >> compiles, links, runs without problems with my gcc.
                    >> And, as far as I remember, it's legal, to compare pointers after
                    >> conversion to long.[/color]
                    >
                    > It just isn't guaranteed to produce any meaningful result.[/color]

                    Why. Please give arguments.

                    Bernhard

                    Comment

                    • Christian Bau

                      #25
                      Re: pointer-in-array test

                      In article <lnptajglui.fsf @nuthaus.mib.or g>,
                      Keith Thompson <kst-u@mib.org> wrote:
                      [color=blue]
                      > By "word pointer", I meant a pointer to a word. There's no necessary
                      > relationship between a integer and a pointer-to-integer -- and the
                      > term "integer" includes all integer types, not just int.
                      >
                      > The concrete example I have in mind is Cray vector systems. A machine
                      > word is 64 bits; there are no instructions that operate directly on
                      > 8-bit bytes. Nevertheless, the C implementation has CHAR_BIT==8, so
                      > it needs to have a way to represent pointers to 8-bit bytes.
                      >
                      > An int* (int is 64 bits) is simply a word pointer with the obvious
                      > representation. If you take an int*, treat it as a 64-bit integer,
                      > increment it, and convert it back to int*, the resulting pointer will
                      > point to the 64-bit word immediately following the original one.
                      >
                      > A char* consists of a word pointer, pointing to the 64-bit word
                      > containing the byte, with a 3-bit byte offset (value 0..7) stored in
                      > the high-order 3 bits (which would otherwise be zero, since no such
                      > system has a large enough address space to need them).[/color]

                      Take a 16 bit x86 system, using the "huge" memory model: A pointer
                      consists of 16 bit segment and 16 bit offset. When the offset exceeds
                      65535, it wraps around to 0 and the segment is increased by eight. So it
                      can happen that

                      (unsigned long) p == 0x3241ffff
                      (unsigned long) (p+1) == 0x32490000

                      Doing pointer arithmetic on unsigned long would prove fatally wrong. In
                      the case above, if p and p+1 are both valid pointers to char objects,
                      then

                      * (char *) (((unsigned long) p) + 1) = '\0';

                      might crash your program. It will definitely not write to p [1].

                      Comment

                      • Bernhard Holzmayer

                        #26
                        Re: pointer-in-array test

                        Thomas Stegen wrote:
                        [color=blue]
                        > Bernhard Holzmayer wrote:
                        >[color=green]
                        >> Sorry,
                        >> pardon me for not checking my code intensively enough.
                        >> I just checked with a 'gcc -pedantic' which didn't throw an error
                        >> :(
                        >>
                        >> What about this solution:
                        >> int ptrInArrSafe(T *p,T *a,int max)
                        >> /* check whether p points to an element of a[max] */
                        >> {
                        >> long px = (long)p;
                        >> long ax = (long)a;
                        >> if (px<ax) return 0; /*out*/
                        >> if (px> (long)&a[max-1]) return 0; /* out */
                        >> if ( (px-ax) % sizeof(T)) return 0; /* not at element
                        >> start*/
                        >> return 1; /* in and on element start */
                        >> }[/color][/color]

                        After a close look to K&R 5.3 and additional sources, I'd like
                        to improve the above a little. What about the following modified
                        version:

                        int ptrInArrSafe(T *p,T *a,int max)
                        /* check whether p points to an element of a[max] */
                        {
                        long index;

                        /* as long as a points to a valid array, this is a legal
                        test for the lower boundary*/
                        if (p<a) return 0; /*out */
                        /* evaluation of element's address is valid for all elements
                        including the virtual last+1 element, though its content may not be
                        retrieved, comparison is legal test for upper boundary */
                        if (!(p<&a[max])) return 0; /* out */

                        /* now we can be sure that we are inside array, because
                        standard requires that array is in a logically "dense" order, from
                        point of logical addresses they must be accessible in ascending
                        order */

                        index = (long)(p - a);
                        /* as far as I understand, it's possible that p-a returns
                        the difference in multiples of sizeof(T), so that if element size
                        were 2, a[2]-a[1] would give 1 instead of 2.
                        Although I never found a compiler doing this, I replace sizeof(T) by
                        a method which should work in both cases. */
                        if ( (p-a) % (&a[1]-&a[0]))
                        return 0; /* not at element boundary*/

                        return 1; /* in and on element boundary */
                        }

                        Bernhard

                        Comment

                        • Irrwahn Grausewitz

                          #27
                          Re: pointer-in-array test

                          Bernhard Holzmayer <holzmayer.bern hard@deadspam.c om> wrote:[color=blue]
                          >Christian Bau wrote:[color=green]
                          >> Bernhard Holzmayer <holzmayer.bern hard@deadspam.c om> wrote:[/color][/color]
                          <snip>[color=blue][color=green][color=darkred]
                          >>> What about this solution:
                          >>> int ptrInArrSafe(T *p,T *a,int max)
                          >>> /* check whether p points to an element of a[max] */
                          >>> {
                          >>> long px = (long)p;
                          >>> long ax = (long)a;[/color][/color][/color]
                          <snip>[color=blue][color=green][color=darkred]
                          >>> compiles, links, runs without problems with my gcc.
                          >>> And, as far as I remember, it's legal, to compare pointers after
                          >>> conversion to long.[/color]
                          >>
                          >> It just isn't guaranteed to produce any meaningful result.[/color]
                          >
                          >Why. Please give arguments.[/color]

                          As has already been pointed out upthread (e.g. by pete in message
                          <4073D355.5C39@ mindspring.com> ), it's implementation-defined if
                          pointer values are meaningfully representable in an object of _any_
                          integral type at all.

                          HTH
                          Regards
                          --
                          Irrwahn Grausewitz (irrwahn33@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 OT guide : http://benpfaff.org/writings/clc/off-topic.html

                          Comment

                          • Bernhard Holzmayer

                            #28
                            Re: pointer-in-array test

                            pete wrote:
                            [color=blue]
                            > Bernhard Holzmayer wrote:
                            >[color=green]
                            >> IMHO you have to use pointer-to-long which must be well-defined
                            >> according to the standard, which means, that a long is big enough
                            >> to hold a pointer on that system. An integer might be too short.[/color]
                            >
                            > Whether or not a pointer can be converted to any integer type
                            > is implementation defined.
                            > The standard does not guarantee that relationships which hold
                            > for two pointers, will also hold for their converted integer
                            > values.
                            >
                            > N869
                            > 6.3.2.3 Pointers
                            > [#6] Any pointer type may be converted to an integer
                            > [#type.
                            > Except as previously specified, the result
                            > is
                            > implementation-defined. If the result cannot be
                            > represented
                            > in the integer type, the behavior is undefined. The
                            > result need not be in the range of values of any integer
                            > type.
                            >[/color]

                            1) Isn't it correct, that long has to be of the size to hold any
                            pointer, so that a conversion:
                            (pType *) --> (void *) ---> (long)
                            and vice versa is legal?

                            2) Isn't it correct, that arrays must have their elements arranged
                            subsequently, so that array == &array[0] and
                            &array[1]>&array[0] are valid?




                            Comment

                            • Bernhard Holzmayer

                              #29
                              Re: pointer-in-array test

                              Bernhard Holzmayer wrote:
                              [color=blue]
                              > Thomas Stegen wrote:
                              >[color=green]
                              >> Bernhard Holzmayer wrote:
                              >>[color=darkred]
                              >>> Sorry,
                              >>> pardon me for not checking my code intensively enough.
                              >>> I just checked with a 'gcc -pedantic' which didn't throw an
                              >>> error
                              >>> :(
                              >>>
                              >>> What about this solution:
                              >>> int ptrInArrSafe(T *p,T *a,int max)
                              >>> /* check whether p points to an element of a[max] */
                              >>> {
                              >>> long px = (long)p;
                              >>> long ax = (long)a;
                              >>> if (px<ax) return 0; /*out*/
                              >>> if (px> (long)&a[max-1]) return 0; /* out */
                              >>> if ( (px-ax) % sizeof(T)) return 0; /* not at element
                              >>> start*/
                              >>> return 1; /* in and on element start */
                              >>> }[/color][/color]
                              >
                              > After a close look to K&R 5.3 and additional sources, I'd like
                              > to improve the above a little. What about the following modified
                              > version:
                              >
                              > int ptrInArrSafe(T *p,T *a,int max)
                              > /* check whether p points to an element of a[max] */
                              > {
                              > long index;[/color]
                              ignore above line![color=blue]
                              >
                              > /* as long as a points to a valid array, this is a legal
                              > test for the lower boundary*/
                              > if (p<a) return 0; /*out */
                              > /* evaluation of element's address is valid for all
                              > elements
                              > including the virtual last+1 element, though its content may not
                              > be retrieved, comparison is legal test for upper boundary */
                              > if (!(p<&a[max])) return 0; /* out */
                              >
                              > /* now we can be sure that we are inside array, because
                              > standard requires that array is in a logically "dense" order, from
                              > point of logical addresses they must be accessible in ascending
                              > order */
                              >
                              > index = (long)(p - a);[/color]
                              ignore above line![color=blue]
                              > /* as far as I understand, it's possible that p-a returns
                              > the difference in multiples of sizeof(T), so that if element size
                              > were 2, a[2]-a[1] would give 1 instead of 2.
                              > Although I never found a compiler doing this, I replace sizeof(T)
                              > by a method which should work in both cases.[/color]
                              Keith, would this hold on your Cray with the strange CHAR
                              representation, that p-a still returns a reasonable result?
                              */[color=blue]
                              > if ( (p-a) % (&a[1]-&a[0]))
                              > return 0; /* not at element boundary*/
                              >
                              > return 1; /* in and on element boundary */
                              > }
                              >
                              > Bernhard[/color]


                              Comment

                              • Irrwahn Grausewitz

                                #30
                                Re: pointer-in-array test

                                Bernhard Holzmayer <holzmayer.bern hard@deadspam.c om> wrote:
                                <snip>[color=blue]
                                >After a close look to K&R 5.3 and additional sources, I'd like
                                >to improve the above a little. What about the following modified
                                >version:
                                >
                                > int ptrInArrSafe(T *p,T *a,int max)
                                > /* check whether p points to an element of a[max] */
                                > {
                                > long index;
                                >
                                > /* as long as a points to a valid array, this is a legal
                                > test for the lower boundary*/
                                > if (p<a) return 0; /*out */[/color]

                                If p and a didn't point into (or one past) the same array in
                                the first place, you already invoked undefined behaviour here
                                (C99 6.5.8#5). All bets off.
                                [color=blue]
                                > /* evaluation of element's address is valid for all elements
                                >including the virtual last+1 element, though its content may not be
                                >retrieved, comparison is legal test for upper boundary */
                                > if (!(p<&a[max])) return 0; /* out */[/color]

                                Ditto.
                                [color=blue]
                                > /* now we can be sure that we are inside array, because
                                >standard requires that array is in a logically "dense" order, from
                                >point of logical addresses they must be accessible in ascending
                                >order */
                                >
                                > index = (long)(p - a);[/color]

                                Forget about the cast. Declare index as ptrdiff_t instead.
                                [color=blue]
                                > /* as far as I understand, it's possible that p-a returns
                                >the difference in multiples of sizeof(T), so that if element size
                                >were 2, a[2]-a[1] would give 1 instead of 2.[/color]

                                That's not only possible, it's /required/ for a conforming
                                implementation to behave like this (C99 6.5.6#9): pointer
                                subtraction always yields values in units of element size.
                                [color=blue]
                                >Although I never found a compiler doing this,[/color]

                                Then you only found non-conforming compilers up until now.
                                [color=blue]
                                >I replace sizeof(T) by
                                >a method which should work in both cases. */
                                > if ( (p-a) % (&a[1]-&a[0]))[/color]

                                Since &a[1]-&a[0] (==a+1-a) always yields 1, the condition
                                is always false.
                                [color=blue]
                                > return 0; /* not at element boundary*/
                                >
                                > return 1; /* in and on element boundary */
                                > }[/color]

                                End of the story: if you ever need to verify if a specific
                                pointed-to object is part of a certain array, carry around
                                the array length plus indices and compare these instead of
                                some 'raw' pointers. And, IMHO, if one feels the need to
                                perform the operation desired by the OP, one should first
                                rethink the algorithm, because it's most probably broken by
                                design.

                                HTH
                                Regards
                                --
                                Irrwahn Grausewitz (irrwahn33@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 OT guide : http://benpfaff.org/writings/clc/off-topic.html

                                Comment

                                Working...