For subtraction of pointers i
and j
to elements of the same array object the note in [expr.add#5] reads:
[ Note: If the value i−j is not in the range of representable values of type
std::ptrdiff_t
, the behavior is undefined. — end note ]
But given [support.types.layout#2], which states that (emphasis mine):
- The type
ptrdiff_t
is an implementation-defined signed integer type that can hold the difference of two subscripts in an array object, as described in [expr.add].
Is it even possible for the result of i-j
not to be in the range of representable values of ptrdiff_t
?
PS: I apologize if my question is caused by my poor understanding of the English language.
EDIT: Related: Why is the maximum size of an array "too large"?
ptrdiff_t is used for pointer arithmetic and array indexing, if negative values are possible. Programs that use other types, such as int, may fail on, e.g. 64-bit systems when the index exceeds INT_MAX or if it relies on 32-bit modular arithmetic.
The subtraction of two pointers is possible only when they have the same data type. The result is generated by calculating the difference between the addresses of the two pointers and calculating how many bits of data it is according to the pointer data type.
Two pointers can also be subtracted from each other if the following conditions are satisfied: Both pointers will point to elements of same array; or one past the last element of same array. The result of the subtraction must be representable in ptrdiff_t data type, which is defined in stddef.
Is it even possible for the result of
i-j
not to be in the range of representable values ofptrdiff_t
?
Yes, but it's unlikely.
In fact, [support.types.layout]/2
does not say much except the proper rules about pointers subtraction and ptrdiff_t
are defined in [expr.add]
. So let us see this section.
[expr.add]/5
When two pointers to elements of the same array object are subtracted, the type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as
std::ptrdiff_t
in the<cstddef>
header.
First of all, note that the case where i
and j
are subscript indexes of different arrays is not considered. This allows to treat i-j
as P-Q
would be where P
is a pointer to the element of an array at subscript i
and Q
is a pointer to the element of the same array at subscript j
. In deed, subtracting two pointers to elements of different arrays is undefined behavior:
[expr.add]/5
If the expressions
P
andQ
point to, respectively, elementsx[i]
andx[j]
of the same array objectx
, the expressionP - Q
has the valuei−j
; otherwise, the behavior is undefined.
As a conclusion, with the notation defined previously, i-j
and P-Q
are defined to have the same value, with the latter being of type std::ptrdiff_t
. But nothing is said about the possibility for this type to hold such a value. This question can, however, be answered with the help of std::numeric_limits
; especially, one can detect if an array some_array
is too big for std::ptrdiff_t
to hold all index differences:
static_assert(std::numeric_limits<std::ptrdiff_t>::max() > sizeof(some_array)/sizeof(some_array[0]), "some_array is too big, subtracting its first and one-past-the-end element indexes " "or pointers would lead to undefined behavior as per [expr.add]/5." );
Now, on usual target, this would usually not happen as sizeof(std::ptrdiff_t) == sizeof(void*)
; which means an array would need to be stupidly big for ptrdiff_t
to overflow. But there is no guarantee of it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With