Subtracting pointers: Which type to use to store the result?

Discussion in 'C Programming' started by Spiro Trikaliotis, Feb 23, 2006.

  1. Hello,

    I have a question regarding subtracting a pointer from another one.
    Assume I have two pointers p1 and p2, which both point to a memory area
    obtained with malloc(). Assume p1 = p2 + some value c.

    Now, I want to obtain the difference between the two, that is, the value
    c. Which type must I use for c?

    I searched around and did not find a definitive answer (not even in the
    FAQ). Anyway, http://c-faq.com/malloc/realloc.html has a code sample
    which uses:

    int tmpoffset;

    p = malloc(10);
    strcpy(p, "Hello,");/* p is a string */
    p2 = strchr(p, ',');/* p2 points into that string */

    tmpoffset = p2 - p;


    Thus, this examples assumes that an int should be sufficient (or that
    example is broken).

    Unfortunately, my compiler complains on the "tmpoffset = p2 -p;" line:

    file.c(745): error C4242: '=' : conversion from '__int64' to 'int', possible loss of data


    (Yes, this is a 64 bit MS compiler, but that should not matter.)

    Of course, I could just use __int64 type, but this does not seem the
    best portable way for me. I could cast p2-p, as I know the difference
    can't be that big not to fit into an int, but this is no good solution
    either. Additionally, I doubt size_t to be a good candidate here,
    either.

    So, my question is: Thinking of portability, which type should I use
    here? Or is the MS compiler wrong?

    Thanks,
    Spiro.

    --
    Spiro R. Trikaliotis http://cbm4win.sf.net/
    http://www.trikaliotis.net/ http://www.viceteam.org/
    Spiro Trikaliotis, Feb 23, 2006
    #1
    1. Advertising

  2. Spiro Trikaliotis

    pemo Guest

    Spiro Trikaliotis wrote:
    > Hello,
    >
    > I have a question regarding subtracting a pointer from another one.
    > Assume I have two pointers p1 and p2, which both point to a memory
    > area
    > obtained with malloc(). Assume p1 = p2 + some value c.
    >
    > Now, I want to obtain the difference between the two, that is, the
    > value
    > c. Which type must I use for c?
    >
    > I searched around and did not find a definitive answer (not even in
    > the
    > FAQ). Anyway, http://c-faq.com/malloc/realloc.html has a code sample
    > which uses:
    >
    > int tmpoffset;
    >
    > p = malloc(10);
    > strcpy(p, "Hello,");/* p is a string */
    > p2 = strchr(p, ',');/* p2 points into that string */
    >
    > tmpoffset = p2 - p;
    >
    >
    > Thus, this examples assumes that an int should be sufficient (or that
    > example is broken).
    >
    > Unfortunately, my compiler complains on the "tmpoffset = p2 -p;" line:
    >
    > file.c(745): error C4242: '=' : conversion from '__int64' to 'int',
    > possible loss of data
    >
    >
    > (Yes, this is a 64 bit MS compiler, but that should not matter.)
    >
    > Of course, I could just use __int64 type, but this does not seem the
    > best portable way for me. I could cast p2-p, as I know the difference
    > can't be that big not to fit into an int, but this is no good solution
    > either. Additionally, I doubt size_t to be a good candidate here,
    > either.
    >
    > So, my question is: Thinking of portability, which type should I use
    > here? Or is the MS compiler wrong?
    >
    > Thanks,
    > Spiro.



    ptrdiff_t


    --
    ==============
    *Not a pedant*
    ==============
    pemo, Feb 23, 2006
    #2
    1. Advertising

  3. pemo wrote:
    > Spiro Trikaliotis wrote:
    > > So, my question is: Thinking of portability, which type should I use
    > > here? Or is the MS compiler wrong?
    > >
    > > Thanks,
    > > Spiro.

    >
    >
    > ptrdiff_t


    And remember to #include <stddef.h>

    --
    BR, Vladimir
    Vladimir S. Oka, Feb 23, 2006
    #3
  4. Spiro Trikaliotis, Feb 23, 2006
    #4
  5. Spiro Trikaliotis

    Alex Fraser Guest

    "Spiro Trikaliotis" <> wrote in message
    news:...
    > I have a question regarding subtracting a pointer from another one.
    > Assume I have two pointers p1 and p2, which both point to a memory area
    > obtained with malloc(). Assume p1 = p2 + some value c.
    >
    > Now, I want to obtain the difference between the two, that is, the value
    > c. Which type must I use for c?


    The result of (p1 - p2) has type ptrdiff_t, but size_t must be able to
    represent this value, since the situation guarantees it is non-negative and
    less than or equal to the size (a value of type size_t) passed to malloc().

    In my experience, the guarantee above is normally the case, and often the
    value is compared with a size_t value, so size_t makes sense to me.

    Alex
    Alex Fraser, Feb 23, 2006
    #5
  6. "Vladimir S. Oka" <> wrote in message
    news:...
    >
    > pemo wrote:
    > > Spiro Trikaliotis wrote:
    > > > So, my question is: Thinking of portability, which type should I use
    > > > here? Or is the MS compiler wrong?
    > > >
    > > > Thanks,
    > > > Spiro.

    > >
    > >
    > > ptrdiff_t

    >
    > And remember to #include <stddef.h>


    Also remember that there is no guarantee that all pointer differences are
    representable as a ptrdiff_t.
    stathis gotsis, Feb 23, 2006
    #6
  7. "Alex Fraser" <> wrote in message
    news:p...
    > "Spiro Trikaliotis" <> wrote in message
    > news:...
    >> I have a question regarding subtracting a pointer from another one.
    >> Assume I have two pointers p1 and p2, which both point to a memory area
    >> obtained with malloc(). Assume p1 = p2 + some value c.
    >>
    >> Now, I want to obtain the difference between the two, that is, the value
    >> c. Which type must I use for c?

    >
    > The result of (p1 - p2) has type ptrdiff_t, but size_t must be able to
    > represent this value, since the situation guarantees it is non-negative
    > and
    > less than or equal to the size (a value of type size_t) passed to
    > malloc().
    >


    No, there is no guarantee that (p1-p2) is non-negative.
    The OP stated " Assume p1 = p2 + some value c"
    He did NOT say that c was positive; as far as we know, it could very well be
    negative.

    > In my experience, the guarantee above is normally the case, and often the
    > value is compared with a size_t value, so size_t makes sense to me.
    >
    > Alex
    >
    >

    --
    Fred L. Kleinschmidt
    Boeing Associate Technical Fellow
    Technical Architect, Software Reuse Project
    Fred Kleinschmidt, Feb 23, 2006
    #7
  8. On 2006-02-23, stathis gotsis <> wrote:
    > "Vladimir S. Oka" <> wrote in message
    > news:...
    >>
    >> pemo wrote:
    >> > Spiro Trikaliotis wrote:
    >> > > So, my question is: Thinking of portability, which type should I use
    >> > > here? Or is the MS compiler wrong?
    >> > >
    >> > > Thanks,
    >> > > Spiro.
    >> >
    >> >
    >> > ptrdiff_t

    >>
    >> And remember to #include <stddef.h>

    >
    > Also remember that there is no guarantee that all pointer differences are
    > representable as a ptrdiff_t.
    >
    >


    What would you use then?


    --
    Remove evomer to reply
    Richard G. Riley, Feb 23, 2006
    #8
  9. Spiro Trikaliotis

    Jordan Abel Guest

    On 2006-02-23, Richard G. Riley <> wrote:
    > On 2006-02-23, stathis gotsis <> wrote:
    >> "Vladimir S. Oka" <> wrote in message
    >> news:...
    >>>
    >>> pemo wrote:
    >>> > Spiro Trikaliotis wrote:
    >>> > > So, my question is: Thinking of portability, which type should I use
    >>> > > here? Or is the MS compiler wrong?
    >>> > >
    >>> > > Thanks,
    >>> > > Spiro.
    >>> >
    >>> >
    >>> > ptrdiff_t
    >>>
    >>> And remember to #include <stddef.h>

    >>
    >> Also remember that there is no guarantee that all pointer differences are
    >> representable as a ptrdiff_t.
    >>
    >>

    >
    > What would you use then?


    Still ptrdiff_t - if it's not representable it'll mess up before you get
    to it, since the type of the expression p2-p1 (given that both p1 and p2
    are pointers to the same type, of course) is ptrdiff_t.
    Jordan Abel, Feb 23, 2006
    #9
  10. Spiro Trikaliotis

    pete Guest

    Richard G. Riley wrote:
    >
    > On 2006-02-23, stathis gotsis <> wrote:
    > > "Vladimir S. Oka" <> wrote in message


    > > Also remember that there is no guarantee
    > > that all pointer differences are
    > > representable as a ptrdiff_t.
    > >
    > >

    >
    > What would you use then?


    I believe that in a conforming program
    which doesn't excede minimum environmental limits,
    you're OK with ptrdiff_t, in C99.

    I wrote some heapsort and quicksort functions,
    that had a part that calculated a pointer difference.
    I felt like making them more robust,
    so I rewrote them with pointers and size_t offsets.

    /* pointier version */
    void q_sort(void *base, size_t nmemb, size_t size,
    int (*compar)(const void*, const void*))
    {
    unsigned char *left, *middle, *last, *right;
    size_t nmemb_right;
    unsigned char *p1, *p2, *end, swap;

    left = base;
    while (nmemb-- > 1) {
    right = left + nmemb * size;
    last = middle = left;
    do {
    middle += size;
    if (compar(left, middle) > 0) {
    last += size;
    BYTE_SWAP(middle, last);
    }
    } while (middle != right);
    BYTE_SWAP(left, last);
    nmemb = (last - left) / size;
    nmemb_right = (right - last) / size;
    if (nmemb_right > nmemb) {
    q_sort(left, nmemb, size, compar);
    left = last + size;
    nmemb = nmemb_right;
    } else {
    q_sort(last + size, nmemb_right, size, compar);
    }
    }
    }

    /* size_t offset version */
    void q_sort(void *base, size_t nmemb, size_t size,
    int (*compar)(const void*, const void*))
    {
    unsigned char *left;
    size_t nmemb_right, middle, last, right;
    unsigned char *p1, *p2, *end, swap;

    left = base;
    while (nmemb-- > 1) {
    right = nmemb * size;
    last = middle = 0;
    do {
    middle += size;
    if (compar(left, left + middle) > 0) {
    last += size;
    BYTE_SWAP(left + middle, left + last);
    }
    } while (middle != right);
    BYTE_SWAP(left, left + last);
    nmemb = last / size;
    nmemb_right = (right - last) / size;
    if (nmemb_right > nmemb) {
    q_sort(left, nmemb, size, compar);
    left += last + size;
    nmemb = nmemb_right;
    } else {
    q_sort(left + last + size, nmemb_right, size, compar);
    }
    }
    }

    #define BYTE_SWAP(A, B) \
    { \
    p1 = (A); \
    p2 = (B); \
    end = p2 + size; \
    do { \
    swap = *p1; \
    *p1++ = *p2; \
    *p2++ = swap; \
    } while (p2 != end); \
    }

    --
    pete
    pete, Feb 23, 2006
    #10
  11. "pete" <> wrote in message
    news:...
    > Richard G. Riley wrote:
    > >
    > > On 2006-02-23, stathis gotsis <> wrote:
    > > > "Vladimir S. Oka" <> wrote in message

    >
    > > > Also remember that there is no guarantee
    > > > that all pointer differences are
    > > > representable as a ptrdiff_t.
    > > >
    > > >

    > >
    > > What would you use then?

    >
    > I believe that in a conforming program
    > which doesn't excede minimum environmental limits,
    > you're OK with ptrdiff_t, in C99.


    I do not understand what you mean by that restriction, but on my system
    where size_t and ptrdiff_t are the same size while the former is unsigned
    and the latter signed, it is clear that not all pointer differences can be
    represented in ptrdiff_t. I think my system is C99 compliant at that point.
    stathis gotsis, Feb 23, 2006
    #11
  12. Fred Kleinschmidt wrote:
    > No, there is no guarantee that (p1-p2) is non-negative.


    I think that that would be a logical error: it's like subtracting two
    dates - if you get a negative result, the you know that something's
    wrong since nothing can ever happen in a negative time. It's the same
    with pointers. If (p1-p2) is negative, you should've said (p2-p1).

    --
    rh
    Richard Harnden, Feb 23, 2006
    #12
  13. Spiro Trikaliotis

    Ben Pfaff Guest

    Richard Harnden <> writes:

    > Fred Kleinschmidt wrote:
    >> No, there is no guarantee that (p1-p2) is non-negative.

    >
    > I think that that would be a logical error: it's like subtracting two
    > dates - if you get a negative result, the you know that something's
    > wrong since nothing can ever happen in a negative time. It's the same
    > with pointers. If (p1-p2) is negative, you should've said (p2-p1).


    I think you have an insufficiently general viewpoint. If you
    subtract date B from date A and get a negative result, you know
    that B is later than A. Similarly, if p1 - p2 is negative, then
    p1 < p2.
    --
    int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
    \n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
    );while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p\
    );}return 0;}
    Ben Pfaff, Feb 23, 2006
    #13
  14. "Richard Harnden" <> wrote in message
    news:...
    > Fred Kleinschmidt wrote:
    >> No, there is no guarantee that (p1-p2) is non-negative.

    >
    > I think that that would be a logical error: it's like subtracting two
    > dates - if you get a negative result, the you know that something's wrong
    > since nothing can ever happen in a negative time. It's the same with
    > pointers. If (p1-p2) is negative, you should've said (p2-p1).
    >
    > --
    > rh

    Well, suppose I use strchr() to search for an 'x' and then again for a 'y'.
    To find out which one came first, I subtract the pointers. The result could
    be either positive or negative, yet there is no reason I "should have"
    known which one would give me the positive value.
    --
    Fred L. Kleinschmidt
    Boeing Associate Technical Fellow
    Technical Architect, Software Reuse Project
    Fred Kleinschmidt, Feb 23, 2006
    #14
  15. Spiro Trikaliotis

    pete Guest

    stathis gotsis wrote:
    >
    > "pete" <> wrote in message
    > news:...
    > >


    > > I believe that in a conforming program
    > > which doesn't excede minimum environmental limits,
    > > you're OK with ptrdiff_t, in C99.

    >
    > I do not understand what you mean by that restriction,


    N869
    4. Conformance
    [#5] A strictly conforming program shall use only those
    features of the language and library specified in this
    International Standard.2) It shall not produce output
    dependent on any unspecified, undefined, or implementation-
    defined behavior, and shall not exceed any minimum
    implementation limit.

    5.2.4.1 Translation limits
    [#1] The implementation shall be able to translate and
    execute at least one program that contains at least one
    instance of every one of the following limits:

    -- 65535 bytes in an object (in a hosted environment only)

    --
    pete
    pete, Feb 23, 2006
    #15
  16. Richard G. Riley wrote:
    >> ...
    >> Also remember that there is no guarantee that all pointer differences are
    >> representable as a ptrdiff_t.
    >>

    >
    > What would you use then?
    > ...


    One should still use 'ptrdiff_t' in general case. The above statement, while
    true, doesn't really work as an argument against using 'ptrdiff_t'. The
    important detail here is that if the pointers are distanced further apart then
    the range of 'ptrdiff_t', then the very attempt to subtract one pointer from
    another _already_ causes the undefined behavior. Note, it is not the attempt to
    store "the overly large number" in the user-specified receiving object of type
    'ptrdiff_t' that causes UB, but it is the very subtraction itself. The UB
    happens "internally".

    In other words, if at certain point the pointers being subtracted happen to be
    too far apart, there's no way to avoid UB, regardless of which type is used to
    store the result.

    There's a popular incorrect opinion that using 'size_t' is guaranteed to work
    without UB in cases when the result of the subtraction is positive.
    Unfortunately, this is not the case. The subtraction itself initially produces a
    value of 'ptrdiff_t', leading to the immediate UB in out-of-range situations.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Feb 23, 2006
    #16
  17. "stathis gotsis" <> writes:
    > "pete" <> wrote in message
    > news:...
    >> Richard G. Riley wrote:
    >> > On 2006-02-23, stathis gotsis <> wrote:
    >> > > "Vladimir S. Oka" <> wrote in message
    >> > > Also remember that there is no guarantee
    >> > > that all pointer differences are
    >> > > representable as a ptrdiff_t.
    >> >
    >> > What would you use then?

    >>
    >> I believe that in a conforming program
    >> which doesn't excede minimum environmental limits,
    >> you're OK with ptrdiff_t, in C99.

    >
    > I do not understand what you mean by that restriction, but on my system
    > where size_t and ptrdiff_t are the same size while the former is unsigned
    > and the latter signed, it is clear that not all pointer differences can be
    > represented in ptrdiff_t. I think my system is C99 compliant at that point.


    That's true only if the implementation actually supports objects whose
    size exceeds SIZE_MAX/2. If size_t is 32 bits, you won't run into
    problems with ptrdiff_t until you have objects of at least 2
    gigabytes. If size_t is 64 bits, I don't think that much memory has
    ever been manufactured.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Feb 23, 2006
    #17
  18. Richard Harnden <> writes:
    > Fred Kleinschmidt wrote:
    >> No, there is no guarantee that (p1-p2) is non-negative.

    >
    > I think that that would be a logical error: it's like subtracting two
    > dates - if you get a negative result, the you know that something's
    > wrong since nothing can ever happen in a negative time. It's the same
    > with pointers. If (p1-p2) is negative, you should've said (p2-p1).


    Not at all.

    Given:
    char foo[100];
    char *p1 = &(foo[20]);
    char *p2 = &(foo[10]);
    we have:
    p1 - p2 == -10
    It's entirely correct and consistent, and it's why ptrdiff_t is
    required to be a signed type.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Feb 23, 2006
    #18
  19. Spiro Trikaliotis

    Alex Fraser Guest

    "Fred Kleinschmidt" <> wrote in message
    news:...
    > "Alex Fraser" <> wrote in message
    > news:p...
    > > "Spiro Trikaliotis" <> wrote in message
    > > news:...
    > >> I have a question regarding subtracting a pointer from another one.
    > >> Assume I have two pointers p1 and p2, which both point to a memory
    > >> area obtained with malloc(). Assume p1 = p2 + some value c.
    > >>
    > >> Now, I want to obtain the difference between the two, that is, the
    > >> value c. Which type must I use for c?

    > >
    > > The result of (p1 - p2) has type ptrdiff_t, but size_t must be able to
    > > represent this value, since the situation guarantees it is non-negative
    > > and less than or equal to the size (a value of type size_t) passed to
    > > malloc().

    >
    > No, there is no guarantee that (p1-p2) is non-negative.
    > The OP stated " Assume p1 = p2 + some value c"
    > He did NOT say that c was positive; as far as we know, it could very well
    > be negative.


    Yes, I assumed that c was non-negative. Even though you've pointed out this
    assumption, I still think it was the OP's intention, due to the phrasing.
    But that's no excuse.

    Alex
    Alex Fraser, Feb 23, 2006
    #19
  20. In article <>,
    Keith Thompson <> wrote:

    > "stathis gotsis" <> writes:
    > > "pete" <> wrote in message
    > > news:...
    > >> Richard G. Riley wrote:
    > >> > On 2006-02-23, stathis gotsis <> wrote:
    > >> > > "Vladimir S. Oka" <> wrote in message
    > >> > > Also remember that there is no guarantee
    > >> > > that all pointer differences are
    > >> > > representable as a ptrdiff_t.
    > >> >
    > >> > What would you use then?
    > >>
    > >> I believe that in a conforming program
    > >> which doesn't excede minimum environmental limits,
    > >> you're OK with ptrdiff_t, in C99.

    > >
    > > I do not understand what you mean by that restriction, but on my system
    > > where size_t and ptrdiff_t are the same size while the former is unsigned
    > > and the latter signed, it is clear that not all pointer differences can be
    > > represented in ptrdiff_t. I think my system is C99 compliant at that point.

    >
    > That's true only if the implementation actually supports objects whose
    > size exceeds SIZE_MAX/2. If size_t is 32 bits, you won't run into
    > problems with ptrdiff_t until you have objects of at least 2
    > gigabytes. If size_t is 64 bits, I don't think that much memory has
    > ever been manufactured.


    Anyway, the result of taking a pointer difference _has_ type ptrdiff_t,
    so if that isn't enough, then you are out of luck, and there is nothing
    you can do. Storing into a type other then ptrdiff_t cannot possibly
    help, because undefined behavior happened earlier.
    Christian Bau, Feb 23, 2006
    #20
    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. Brian Henry
    Replies:
    6
    Views:
    16,154
    Brian Henry
    Nov 19, 2003
  2. =?Utf-8?B?TWFubnkgQ2hvaGFu?=

    subtracting days from date

    =?Utf-8?B?TWFubnkgQ2hvaGFu?=, Nov 8, 2004, in forum: ASP .Net
    Replies:
    5
    Views:
    27,443
    =?Utf-8?B?QmlsbCBCb3Jn?=
    Nov 9, 2004
  3. Martin Joergensen

    subtracting pointers...

    Martin Joergensen, May 1, 2006, in forum: C Programming
    Replies:
    3
    Views:
    367
    Michael Brennan
    May 1, 2006
  4. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    651
  5. Michael Tan
    Replies:
    32
    Views:
    925
    Ara.T.Howard
    Jul 21, 2005
Loading...

Share This Page