Chris Vine <chris@cvine--nospam--.
freeserve.co.uk> writes:
>On Tue, 09 Jun 2015 13:59:41 GMT
>sc...@slp53.sl.home (Scott Lurndal) wrote:
>> It was added to POSIX/SUS to accomodate interfaces that returned
>> a negative value of one on error a quarter of a century ago.
>>=20
>> Now the standard actually requires ssize_t to support the range
>> [-1, {SSIZE_MAX}], but in practice, no modern implementation
>> supports only a single negative value (this wording was added
>> due to one, no longer available, implementation when we added
>> ssize_t), and in any case, that constraint is sufficient for the
>> aforementioned loop.
>>=20
>> The competent programmers at microsoft defined it as unsigned in
>> Visual Studio 2010, which may have put some people off using it
>> (subsequently fixed).
>
>ssize_t is poorly implemented in POSIX and has rightly not been
>incorporated into either C or C++.
>
>Take the most basic of POSIX functions, namely read(). It takes a
>second count argument of type size_t, indicating the maximum number of
>bytes that the read buffer can take, and returns a ssize_t type
>representing (if positive) the number of bytes read or -1 in case of
>error. Because std::size_t/SIZE_MAX is required by the C and C++
>standards to be wide enough to take the maximum addressable size of an
>object, this means that a call to read() with a count argument greater
>than SSIZE_MAX and less than SIZE_MAX will result in an overrun
>generating undefined behaviour (=C2=A74.7/3). So the typing actually
>operates to reduce safety rather than increase it.
>
>ssize_t should generally be avoided where not mandated as part of a
>POSIX interface that a program is obliged to use.
>
The abstract type ssize_t was added long after the interfaces which
used it were defined (e.g. the read(2) system call return value was
defined as a 16-bit signed integer in V6 (late 70's)). When 32-bit
systems became prevalent, int was extended to 32-bits (not without
some painful work fixing broken apps). Meanwhile, X/Open, POSIX, etc.
needed to abstract the return type for read, write et. alia to allow
for future software portability[*], and because legacy software needed
to see -1 as a return code from read on error, an abstract type
(ssize_t) was defined.
ssize_t "This is intended to be a signed analog of size_t. The
wording is such that an implementation may either choose
to use a longer type or simply to use the signed version
of the type that underlies size_t. All functions that
return ssize_t {read() and write()} describe as
'implementation defined' the result of an input exceeding
{SSIZE_MAX}. It is recognized that some implementations
might have 'int' that are smaller than size_t. A portable
application would be constrained to not perform I/O in
pieces larger than {SSIZE_MAX}, but a portable application
using extensions would be able to use the full range if
the implementation provided an extended range, while still
having a single type-compatible interface."
[P1003.4/D14.1 May 1993]
This has been well-known for a quarter century.
Given {SSIZE_MAX} on modern 64-bit systems, restricting I/O to
{SSIZE_MAX} doesn't seem to be a limiting constraint.
Without changing 20+ years of legacy unix code, there was no other
solution. You can bitch about it all you want, but it is what it is.
[*]
http://www.unix.org/version2/whatsnew/lfs20mar.html