Paul Eggert wrote:
> #include <stdint.h>
> #include <stddef.h>
> #include <stdlib.h>
> 
> ptrdiff_t
> diff (short *a, short *b)
> {
>    return a - b;
> }
> 
> int
> main (void)
> {
>    size_t n = PTRDIFF_MAX / sizeof (short) + 1;
>    short *x = malloc (n * sizeof (short));
>    return 0 < diff (x + n, x);
> }

I can reproduce it, on Ubuntu with "gcc -m32", even with a 2.5 GB allocation:
     size_t n = PTRDIFF_MAX / sizeof (short) * 1.25;
'ltrace' shows that malloc succeeds.

The code of the 'diff' function shows a signed shift:

diff:
        movl    4(%esp), %eax
        subl    8(%esp), %eax
        sarl    %eax
        ret

And indeed, an unsigned shift is not possible here because the compiler
doesn't know whether to expect a >= b or a <= b. 

So, the limiting factor is the pointer difference operator
   ptr1 - ptr2        where sizeof (*ptr1,*ptr2) > 1.

Consequences:

* We have no problem with code that only works with indices and never does
  pointer differences or pointer comparisons.

    for (i = 0; i < n; i++)
      do_something (&array[i]);

  is better than

    array_end = &array_end;
    for (p = array; p < array_end; p++)
      do_something (p);

  But does GCC's strength-reduction optimization know this?

* We have no problem with strings, because sizeof (char) == 1.

Bruno


Reply via email to