[1]: http://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/...
> only guaranteed to have the range [-1, SSIZE_MAX]
Oh, that's a weird type. I wonder if any compiler implementation encodes it with -1 bias, so that all bits 0 means "-1".
It could cause a disaster if/when ssize_t is encoded as anything else but standard twos complement signed number...
0xFC SSIZE_MAX - 2
0xFD SSIZE_MAX - 1
0xFE SIZE_MAX
0xFF -1
That makes more sense to me than a bias that the compiler would have to know about.Obvious (well, relatively), but alas non-trivial to fix in a codebase of even moderate size. (5k+ LoC, let's say)
Implicit integral conversions are one of the worst things ever foisted upon the programming world... and that's saying something (given the existence of NULL). Well, that and the whole size_t == unsigned <whatever> thing[1].
[1] I can certainly agree that it was useful when it was introduced because it actually doubled your addressable storage in a practical way, but does any existing machine address even close to 64-bit? For context: 60-bits of addressability is ~1000PB.
The only problem is that there's lots of software written before those types even existed, and even today people might learn a bad style from old code. The problem is that compilers hardly compel one to use a good coding style.
Ideally the compiler would do a check during a conversion from a negative signed integer to unsigned integer, and set a flag or throw some sort of exception. Hopefully future languages (e.g. Rust) learn from this.
https://curl.haxx.se/docs/adv_20160914.html
"The provided string length arguments were not properly checked and due to arithmetic in the functions, passing in the length 0xffffffff (2^32-1 or UINT_MAX or even just -1) would end up causing an allocation of zero bytes of heap memory that curl would attempt to write gigabytes of data into."
Some typical points to consider:
1) Never store a length as an int, unsigned, long, etc. Use size_t (or ssize_t) instead.
2) Never store a pointer as an int, unsigned, long, etc. Use uintptr_t (or intptr_t). ptrdiff_t is the type to use for pointer differencing.
3) When comparing or casting to a signed type, watch out for sign extension. For example (short) -1 (0xffff) becomes 2^32-1 (0xffffffff) when casted to uint32_t. Remember char is usually a signed type.
4) Some legacy library functions return int, which is a signed 32-bit value in Windows and Linux (remember point 3). Watch out for these cases. For example don't use ftell and check s[n]printf return value.