34

According to http://en.cppreference.com/w/cpp/io/streamsize

The type std::streamsize is a signed integral type used to represent the number of characters transferred in an I/O operation or the size of an I/O buffer.

As far as I can imagine, a stream's size can never be negative, so, my question is:

Why is std::streamsize defined as signed rather than unsigned? What's the rationale behind?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
xmllmx
  • 39,765
  • 26
  • 162
  • 323

1 Answers1

26

The draft C++ standard has the following footnote 296 in section 27.5.2 Types which says:

streamsize is used in most places where ISO C would use size_t. Most of the uses of streamsize could use size_t, except for the strstreambuf constructors, which require negative values. It should probably be the signed type corresponding to size_t (which is what Posix.2 calls ssize_t).

and we can see in section D.7.1.1 strstreambuf constructors we have the following entries (emphasis mine going forward):

strstreambuf(char* gnext_arg, streamsize n, char *pbeg_arg = 0);
strstreambuf(signed char* gnext_arg, streamsize n,
   signed char *pbeg_arg = 0);
strstreambuf(unsigned char* gnext_arg, streamsize n,
   unsigned char *pbeg_arg = 0);

and says:

gnext_arg shall point to the first element of an array object whose number of elements N is determined as follows:

and we can see from the following discussion that n which is of type streamsize is indeed required to be able to take on a negative value:

— If n > 0, N is n.

— If n == 0, N is std::strlen(gnext_arg).

If n < 0, N is INT_MAX.336

This seems like a poor argument for this requirement and the closed issue 255 has a similar comment from Howard Hinnant which says:

This is something of a nit, but I'm wondering if streamoff wouldn't be a better choice than streamsize. The argument to pbump and gbump MUST be signed. [...] This seems a little weak for the argument to pbump and gbump. Should we ever really get rid of strstream, this footnote might go with it, along with the reason to make streamsize signed.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 15
    It seems too heavy and counter-intuitive to define `std::streamsize` as signed ONLY FOR supporting such an special case. – xmllmx Jun 30 '14 at 02:12
  • 2
    @xmllmx Howard Hinnant seems to agree with you but it looks like the committee choose to leave it as is at the time. – Shafik Yaghmour Jun 30 '14 at 02:21
  • 4
    the return type of `std::count` is good design. it's signed. it would require some rationale to make it unsigned, since unsigned is associated with unfortunate promotions in mixed type expressions and therefore a bit risky, as attested by usual compiler warnings for comparisons. – Cheers and hth. - Alf Jun 30 '14 at 02:46
  • 4
    in short, it's rather silly to argue about "the" reason to make the type signed. signed is the default non-problematic choice. no valid reason to make it unsigned has been presented. – Cheers and hth. - Alf Jun 30 '14 at 02:49
  • 2
    @Cheersandhth.-Alf I don't quite follow you, the standards committee provides two separate pieces of information regarding the rationale for this feature. They themselves seemed to think it was odd enough to have a *size type* be signed they put in a footnote to explain. – Shafik Yaghmour Jun 30 '14 at 04:19
  • Actually, this is not quite right (well, or else I am misremembering). I thought that a `ssize_t` is ***not*** guaranteed to be the signed version of `size_t`. The Standard guarantees only that it must be large enough to represent `-1` in addition to the `size_t` values. In practice, it is indeed a signed version of `size_t` in any implementation I have ever seen, but the Standard does not require that it be so. To be honest, I’d hate to see how it would be done any other way, but you never know. – tchrist Jun 30 '14 at 05:26
  • @tchrist interesting, I will have to look at that when I have some more time. – Shafik Yaghmour Jun 30 '14 at 09:24
  • @tchrist: re "the standards committee provides two separate pieces of information regarding the rationale for this feature", that may be but such *has not been presented here*. 1st, if you think howard's comment is about rationale for signed, note that in c++11 `streamoff` which he suggests is also signed: it's a comment about needless redundancy in c++11 (in c++03 there was a need for distinct types). and if you think the footnote here called 296 is about the rationale, no, it's merely descriptive, although it implies that there must be some rationale for this deviation from convention in C. – Cheers and hth. - Alf Jun 30 '14 at 14:11
  • The fact that streamsize is unsigned causes real problems when reading std::string from stream. In my asio code I get : ` c++/v1/istream:1465:23: runtime error: implicit conversion from type 'std::basic_string::size_type' (aka 'unsigned long') of value 18446744073709551599 (64-bit, unsigned) to type 'std::streamsize' (aka 'long') changed the value to -17 (64-bit, signed)` from clang sanitizer. And in the istream file I can see : `__n = __str.max_size();` where __n is steamsize and max_size() returns string::size_type. What saves the situation is a line below which fixes value: ... – marcinj Apr 15 '22 at 16:26
  • .... if (__n <= 0) __n = numeric_limits::max(); :-) – marcinj Apr 15 '22 at 16:26