Array Index Greater Than PTRDIFF_MAX

- 1 answer

Let's have a char array:

char arr[(size_t)PTRDIFF_MAX + (size_t)2];

And let's accept that we have a system with sufficient memory available.

Accessing the array either in array notation or pointer notation is defined, undefined, or implementation defined behaviour?

char c = arr[(size_t)PTRDIFF_MAX + (size_t)1];
char d = *(&arr[0] + ((size_t)PTRDIFF_MAX + (size_t)1));

I'm concerned that the index may be converted to ptrdiff_t before the access resulting in an invalid index.


In the case there's no possibility of having an array of that many elements, let's put this similar situation:

We have an array of less elements than PTRDIFF_MAX, but big ones (e.g.: int64_t, or structs with many elements), such that the raw size of the array still exceeds PTRDIFF_MAX. And we access the array through a char *, which is a valid cast (more or less what's happening inside memcpy).



The array index is not converted to ptrdiff_t.

Adding an integer to a pointer is done with the actual value (including signedness) of the integer addend, so array indexing is not a problem. (Of course, you have to ensure that the type of the index you provide is adequately wide and that the value is within the range of legal index values. But if that's the case, the compiler isn't going to change the type.)

The problem may arise when you are subtracting pointers; in that case, if the result of the subtraction is not representable as a ptrdiff_t, then the outcome is undefined. But remember the the result is the number of array elements, not the number of bytes. Of course, if it is an array of char, there's no difference, but for array element types whose size is greater than 1 it is not possible to overflow, assuming that ptrdiff_t is the signed version of size_t.

The standard is explicit about the result of pointer subtraction:

if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. (§6.5.6p9).

That wording goes out of its way to emphasize that it is the difference between array indices, and not the difference of the addresses, which must fit in a ptrdiff_t.