std::ifstream::read(char_type*, std::streamsize)std::streamsize接受使用有符号类型和std::fread(void*, std::size_t, std::size_t, std::FILE*)- 使用无符号类型读取的字节数std::size_t。同时,在许多示例中,无论是那里还是那里,对于字节数,他们都使用sizeof,结果为std::size_t. 大小std::vector<char>也是无符号的。那么为什么这个函数采用有符号类型呢?如何正确转换类型以毫无问题地填充字节向量?
我认为正确的答案是它发生在历史上。一开始,C/C++ 积极地将 int 用于一切(在旧 C 中,它通常是“默认类型”)。甚至没有人想到某些文件会大于 2 GB(“这些都是巨大的大小”)——现在他们认为大约 64 分之二。此外,使用负数作为错误的标志非常方便. 如果读取了某些内容,则相同的 read/ recv返回正数,如果文件/套接字关闭则返回零,如果发生错误则返回负数。这很方便。
但随后数学家们看着它说:“好吧,数组的大小怎么可能是负数?” 另外,当我们尝试添加两个数组大小时会导致错误,其中一个是负数(因为它实际上是读取错误的字节数)。并且决定最好存储在无符号类型中,并以另一种方式返回错误(例如,带有异常或返回代码)。但不是每个人都这样,java中没有无符号类型(或者它们已经出现了?)。
即便如此,许多人还是不想因为错误而放弃惯用的 -1。从好的方面来说,有很多地方使用 0xFFF...FF 来准确地指示错误,这有时会导致很酷的错误(尝试分配如此多的内存通常以没有好处的结果而告终)。
然后标准化委员会的聪明人又看了一遍,决定,别装了,我们加ssize——和size一样,只是一个标志。有一些有趣的事情可以解释为什么这一切都是必要的。
该类型
std :: streamsize是一个有符号整数类型,用于表示在 I/O 操作中传递的字符数或 I/O 缓冲区的大小。它用作签名对应物std :: size_t,类似于 POSIX 类型ssize_t。除了构造函数,从不使用
std :: strstreambuf负值。std :: streamsizeC++ 草案标准在第 27.5.2 节类型中有以下脚注 296,其中说:
streamsize在 ISO C 将使用的大多数地方使用size_t.streamsize可以在大多数情况下使用size_t,除了strstreambuf需要负值的构造函数。它可能应该是一个有符号类型,对应size_t(这就是 Posix.2 所称的ssize_t)。我们看到在D.7.1.1构造函数
strstreambuf中我们有以下条目:并说:
gnext_arg必须指向数组对象的第一个元素,其元素数 N 定义如下:从下面的讨论中,我们可以看到 n 的类型
streamsize确实需要能够取负值:我不会判断该类型是有符号整数类型是如何发生的
std::streamsize,但是,我会注意到,即使它是无符号的,那么您的主要问题 - “正确的类型转换” - 将无法以任何方式解决。语言标准不保证
std::size_t都可以用该类型来表示std::streamsize,std::streamsize都可以由该类型表示std::size_t,std::vector<some_type>由类型表示std::streamsize,std::streamsize都可以用一个类型来表示std::vector<some_type>::difference_typestd::size_t都可以由该类型表示std::vector<some_type>::size_type。因此,为了完全确保在将一种类型的值转换为另一种类型的值时,不会发生意外截断,您应该在转换之前检查转换后的值是否适合目标类型。
例如明确地:
甚至像这样:
顺便说一句,向量中元素的最大数量是从上面以某个有符号整数类型的最大值为界的
std::vector<some_type>::difference_type。这是因为该方法max_size()返回的值等于distance(begin(), end())某个最大可能向量的值。请参阅:container.requirements.general/4。Astd::distance返回有符号整数类型的值difference_type。