问题
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:
- Secure coding
- Is subtraction of pointers not pointing to different elements of same array valid in C?
However, no mention of it is made in these SO questions:
- Pointer subtraction confusion
- size_t return pointer subtraction
- Pointer Arithmetic In C
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?
回答1:
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).
回答2:
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 [...]"
回答3:
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.
来源:https://stackoverflow.com/questions/12099719/when-is-pointer-subtraction-undefined-in-c