Re:About size_t and ptrdiff_t
by gjm11 on Tuesday August 18, 2015 @02:39PM
(#10081232)
Let me enumerate the worst errors in this article.
1. Their "headline" recommendation near the start is that you should write things like for (ptrdiff_t i=0; i<...; ++i) { ... a[i]; ... }. No, for this purpose you should almost certainly be using size_t rather than ptrdiff_t. The article nowhere gives any reason for preferring ptrdiff_t to size_t in this context. (There might be some; e.g., if you're processing that array in reverse order, you might want to test whether i>=0, and that won't give useful results if i is of an unsigned type. But you won't learn that from the article.)
2. The article claims that size_t and uintptr_t are synonyms, and likewise for ptrdiff_t and intptr_t. I dare say in practice they're always equivalent types, but they certainly don't mean the same thing and encouraging readers to think they do is a bad idea.
3. Similarly, the article says that a size_t or ptrdiff_t "can store a pointer". There are -- as the article admits -- integral types actually guaranteed to be usable in this way, namely intptr_t and uintptr_t. There is no guarantee that you can do that with size_t or ptrdiff_t, and no good reason why you should try.
4. The article says that ptrdiff_t "could store the maximum size of a theoretically possible array of any type". No, that would be size_t.
5. The article lists things that size_t and ptrdiff_t are "usually used for". The difference between the two lists is that the one for ptrdiff_t includes "size storage", which is exactly backwards. (You'd think the name size_t might be a clue.)
6. Those lists include, in both cases, "storing pointers". No: use pointer types for storing pointers, and if you really truly need to force them into integral types then use intptr_t or uintptr_t.
7. In the second example of a "sleeping error" -- the one with variables A and B -- the more fundamental problem isn't the failure to use size_t/ptrdiff_t, it's the fact that the expression A+B is of an unsigned type but is being used to hold a negative array offset. It's true that using size_t instead of unsigned will probably make the error go away, but the right way to make it go away is never to have the equivalent of ((unsigned)-2) in your code to begin with. You want a signed type for that, and int will do just as well as ptrdiff_t.
8. The final section of the article makes it clear that its real goal is to convince developers that (1) we should use size_t and ptrdiff_t if we care at all about portability and future-proofing, but (2) converting code to do so is too painful for human beings, so (3) you should buy their product.
It's maybe a bit unfair to classify that as an "error", but I don't think I would want to entrust static analysis of integer-type issues to software written by someone who could write this article.
1. Their "headline" recommendation near the start is that you should write things like for (ptrdiff_t i=0; i<...; ++i) { ... a[i]; ... }. No, for this purpose you should almost certainly be using size_t rather than ptrdiff_t. The article nowhere gives any reason for preferring ptrdiff_t to size_t in this context. (There might be some; e.g., if you're processing that array in reverse order, you might want to test whether i>=0, and that won't give useful results if i is of an unsigned type. But you won't learn that from the article.)
2. The article claims that size_t and uintptr_t are synonyms, and likewise for ptrdiff_t and intptr_t. I dare say in practice they're always equivalent types, but they certainly don't mean the same thing and encouraging readers to think they do is a bad idea.
3. Similarly, the article says that a size_t or ptrdiff_t "can store a pointer". There are -- as the article admits -- integral types actually guaranteed to be usable in this way, namely intptr_t and uintptr_t. There is no guarantee that you can do that with size_t or ptrdiff_t, and no good reason why you should try.
4. The article says that ptrdiff_t "could store the maximum size of a theoretically possible array of any type". No, that would be size_t.
5. The article lists things that size_t and ptrdiff_t are "usually used for". The difference between the two lists is that the one for ptrdiff_t includes "size storage", which is exactly backwards. (You'd think the name size_t might be a clue.)
6. Those lists include, in both cases, "storing pointers". No: use pointer types for storing pointers, and if you really truly need to force them into integral types then use intptr_t or uintptr_t.
7. In the second example of a "sleeping error" -- the one with variables A and B -- the more fundamental problem isn't the failure to use size_t/ptrdiff_t, it's the fact that the expression A+B is of an unsigned type but is being used to hold a negative array offset. It's true that using size_t instead of unsigned will probably make the error go away, but the right way to make it go away is never to have the equivalent of ((unsigned)-2) in your code to begin with. You want a signed type for that, and int will do just as well as ptrdiff_t.
8. The final section of the article makes it clear that its real goal is to convince developers that (1) we should use size_t and ptrdiff_t if we care at all about portability and future-proofing, but (2) converting code to do so is too painful for human beings, so (3) you should buy their product.
It's maybe a bit unfair to classify that as an "error", but I don't think I would want to entrust static analysis of integer-type issues to software written by someone who could write this article.