When is pointer subtraction undefined in C?

char *buf = malloc(bufsize)
char *ptr = buf;
…
while(condition) {
    ptrdiff_t offset = ptr - buf;    // <========== THIS LINE

    // offset will never be negative because we only ever *increase* ptr
    if ((size_t)offset > bufsize) {
        // we need more room
        bufsize += 128;
        buf = realloc(buf, bufsize);
        ptr = buf + offset;  // buf might be in a completely new location
    }
    *ptr++ = …  // write this byte
}

Is this valid or undefined?

I would have assumed that it's valid, but I read something about it being undefined, so I googled it. These links seem to inescapably claim it's undefined:

However, no mention of it is made in these SO questions:

These all talk about not two pointers being in the same "array". Does that actually mean a plain old C array on the stack?

If it is undefined, it seems very odd to me… Why force me to carry along a counter variable when I have access to one constant pointer and one moving pointer?

Answers


Pointers into a block of memory returned by malloc count as being into the same array:

c11

7.22.3 Memory management functions

1 - The pointer returned [from malloc] if the allocation succeeds [...] may be assigned to a pointer to any type of object [...] and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).


ptrdiff_t offset = ptr - buf;    // <========== THIS LINE

This is perfectly defined behavior.

(C99, 6.5.6p9) "When two pointers are subtracted, both shall point to elements of the same array object [...]"


It's defined behavior, as long as you don't go farther than one element past the end of the array. C99 §6.5.6/8 says this about adding a pointer and an integer:

[...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. [...]

And paragraph 9, on subtraction:

9) When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; [...]

And from §7.20.3/1:

The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).

So once you move ptr to point beyond the element after the last array element, doing the pointer subtraction is undefined behavior.

I do believe there are systems out there that would behave badly with this code, although I can't name any. In theory, malloc() could return a pointer to just before the end of addressable memory, e.g. if you ask for 255 bytes it could return 0xFFFFFF00 on a 32-bit system, so creating a pointer beyond the end will lead to overflow. It's also possible that integer overflow on pointer representations can trigger a trap of some sort (e.g. if pointers are stored in special registers). While I don't know of any systems with these properties, the C standard certainly allows for their existence.


Need Your Help

Drive JS API Realtime sample example is not behaving as expected

google-drive-api google-drive-realtime-api

Well i have just tried the sample example of real time js Google drive api. As they said in their tutorial,the application's text areas will be synced even if they are opened in different browser w...