0

If ptrdiff_t were unsigned, it would be able to refer to twice as many elements. On my machine PTRDIFF_MAX is expanded to 9223372036854775807i64, whereas ULLONG_MAX is 18446744073709551615Ui64.

I know that these values are huge themselves, but if

The type (ptrdiff_t)'s size is chosen so that it can store the maximum size of a theoretically possible array of any type.

ref

then doesn't making it unsigned make more sense?

cigien
  • 57,834
  • 11
  • 73
  • 112
ZoomIn
  • 1,237
  • 1
  • 17
  • 35
  • 2
    Because it's a result of the substraction by its definition. – 273K Aug 16 '22 at 01:57
  • 4
    How would you handle a negative offset? – David C. Rankin Aug 16 '22 at 01:57
  • 3
    Sounds like imprecise wording on someone's blog from over a decade ago. The actual motivation behind [std::ptrdiff_t](https://en.cppreference.com/w/cpp/types/ptrdiff_t) is to allow the _difference_ between two points, which might be a negative number if the first pointer is actually after the second. If a signed type was used, there'd be no difference from `std::size_t` – Nathan Pierson Aug 16 '22 at 01:58
  • Your quote about `ptrdiff_t` bears similarity to what cppreference.com has to say about [`size_t`](https://en.cppreference.com/w/cpp/types/size_t) -- *"`std::size_t` can store the maximum size of a theoretically possible object of any type (including array)"*, and cppreference.com gives a different motivation for [`ptrdiff_t`](https://en.cppreference.com/w/cpp/types/ptrdiff_t) -- *"[pointer arithmetic](https://en.cppreference.com/w/cpp/language/operator_arithmetic#Additive_operators)"*. Which source is to be believed? – JaMiT Aug 16 '22 at 02:01
  • @DavidC.Rankin `int arr[5]; int *a = arr + 1, *b = arr + 3; std::cout << a - b;` – NathanOliver Aug 16 '22 at 02:05
  • @DavidC.Rankin Yeah, but even with signed, negative offset is problematic right? – ZoomIn Aug 16 '22 at 02:06
  • @JaMiT sorry, not sure either! – ZoomIn Aug 16 '22 at 02:07
  • @NathanOliver It makes perfect sense now, because if ptrdiff_t is undefined, it can't hold negative offsets. – ZoomIn Aug 16 '22 at 02:10
  • 2
    @ZoomIn - not necessarily. So long as you are within a valid memory block, you are free to use any number of pointers. Subtracting two that yield a negative offset within the valid block is not a problem. (You do need to protect against attempting to access an address before or after your valid block) – David C. Rankin Aug 16 '22 at 02:14
  • @NathanOliver Yeah, guess I was looking at imprecise information, interestingly it was Google's answer for my search! Your explanation makes more sense, thank you. – ZoomIn Aug 16 '22 at 02:15
  • 3
    @ZoomIn -- Google is NOT a C++ reference, [cppreference.com](https://en.cppreference.com/w/Main_Page) is `:)` – David C. Rankin Aug 16 '22 at 02:18
  • 1
    Note that the maximum size of an object is less that `std::size_t` or `std::intptr_t` can hold. The maximum size of an object is actually limited by what `std::ptrdiff_t` can represent. Also note that hardware doesn't even come close to allowing objects of the maximum size. The virtual address space is usually far smaller. – Goswin von Brederlow Aug 16 '22 at 02:37
  • @GoswinvonBrederlow Yeah, I was thinking about those limitations too, but was trying to keep the question concise and hoping someone would talk about it too. – ZoomIn Aug 16 '22 at 02:45
  • 1
    `std::ptrdiff_t` is defined as holding the result of subtracting two pointers - not an array index and not the number of elements in an array. Making `std::ptrdiff_t` a signed type allows addition and subtraction to be inverses/opposites of each other (and adding a `std::ptrdiff_t` to a pointer gives back a pointer). For example, if we have an array `a` with ten elements, `p = &a[9] - &a[0]` has type `std::ptrdiff_t` and both the identities `&a[0] + p == &a[9]` and `&a[0] == &a[9] - p` are *guaranteed* to be true - which would not be possible if `std::ptrdiff_t` was an unsigned type. – Peter Aug 16 '22 at 04:20
  • A limit is imposed by reflecting the natural sign of the difference. But please remember the size on the OP's platform is sufficient to represent differences within a single contiguous character array of 8191 pebitbytes. The largest computer in the world currently has 160 terabytes of memory which 50,000 times smaller than that limit. This is a genuine limitation but a necessary one and typically irrelevant. – Persixty Aug 16 '22 at 07:55

1 Answers1

2

If ptrdiff_t were unsigned, it would be able to refer to twice as many elements.

That is not correct. Making a type unsigned does not magically increase the amount of information it can hold. Signed and unsigned integers of the same size have exactly the same number of different states. In the signed version, half the states represent negative numbers. And you do need negative numbers to handle the result of subtracting a pointer with a higher address value from one with a lower address value. For instance:

int arr[42];
int* p1 = arr;
int* p2 = arr + 42;
auto diff = p1 - p2; // what should the result be?
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93