Using ptrdiff_t
std::ptrdiff_t is used for both pointer arithmetic and array indexing. Code that uses other data types, such as integer, may fail on 64-bit processors when the underlying array is very large and the index exceeds INT_MAX. Let's look at some of these important numbers:
printf(“Maximum value for int is %d\n”, std::numeric_limits<int>::max()); printf(“Maximum value for unsigned short is %d\n”, std::numeric_limits<unsigned short>::max()); printf(“Value of 2 to the power of 30 is 1GByte, i.e.,%f\n”, pow(2.0, 30)); printf(“Maximum value for unsigned int is %u\n”, std::numeric_limits<unsigned int>::max()); printf(“Value of PTRDIFF_MAX is %ld\n”, std::numeric_limits<std::ptrdiff_t>::max());
Here's the output from this code:
Maximum value for int is 2147483647 Maximum value for unsigned short is 65535 Value of 2 to the power of 30 is 1GByte, i.e., 1073741824 Maximum value for unsigned int is 4294967295 Value of PTRDIFF_MAX is 9223372036854775807
Notice the very restricted range of an unsigned short (maximum value 65535). This is unlikely to cut it in the wide-open 64-bit spaces of big arrays! The danger with a legacy array indexed by an unsigned short is that it may be all too easy to overrun the array boundary. This can happen in a quite subtle way, where an attempt to access the 64-bit array exceeds 65535. Why is it subtle? Well, once the range exceeds 65535, the unsigned short index value can loop back to zero. This is quite easy to see in an example:
unsigned short a[std::numeric_limits<unsigned short>::max()]; printf(“Number of array elements %u\n”, sizeof(a)/sizeof(unsigned short)); // We now deliberately exceed the array boundary for (unsigned int i = 0; i < std::numeric_limits<unsigned short>::max() + 3; i++) { if (i >= std::numeric_limits<unsigned short>::max()) { printf(“Exceeding range at i = %u\n”, i); } a[i] = i; if (i >= std::numeric_limits<unsigned short>::max()) { printf(“Value of array at i = %u\n”, a[i]); } }
This code produces the following output:
Number of array elements 65535 Exceeding range at i = 65535 Value of array at i = 65535 Exceeding range at i = 65536 -------> Here, we get wraparound back to zero Value of array at i = 0 Exceeding range at i = 65537 Value of array at i = 1
Imagine if we were looping through this array using an integer index. When the index value exceeds the range of unsigned short, we are then exceeding the array boundary. In the above case, the index wraps around to zero, after which we might inadvertently start overwriting the existing values.
Neither of these situations is desirable, although when you exceed an array boundary, the code may cause a segmentation fault. The latter may possibly be more helpful in trying to find the source of the problem, but there's no guarantee it will happen in a useful way.
This issue of index-value range is one reason why 64-bit arrays should be indexed using the data type std::ptrdiff_t. Remember, this type has a maximum limit:
Value of PTRDIFF_MAX is 9223372036854775807
Plenty of headroom there, with no risk of wraparound.