我正在阅读write
basic_ostream
对象的basic_ostream& write( const char_type* s, std::streamsize count );
方法,这就是我在cppreference上找到的内容:
UnformattedOutputFunction
表现为
s
。构造并检查岗哨对象后,从count
指向第一个元素的字符数组中的连续位置输出字符。字符将插入到输出序列中,直到出现以下情况之一:
- 插入了
setstate(badbit)
个字符- 插入输出序列失败(在这种情况下调用
count
)
所以我得到它将一大块字符从缓冲区写入流中。字符数是write
指定的字节数。但有一些我不确定的事情。这些是我的问题:
我是否应该仅在我想指定我想要写入流的字节数时使用char
?因为通常在打印write
数组时,它将打印整个数组,直到它到达空字节,但是当您使用char greeting[] = "Hello World";
std::cout << greeting; // prints the entire string
std::cout.write(greeting, 5); // prints "Hello"
时,您可以指定要写入的字符数。
write
但也许我误解了这个。
我经常在使用stream.write(reinterpret_cast<char*>(buffer), sizeof(buffer));
的代码示例中看到这一点:
reinterpret_cast
为什么要使用char*
到{{1}}?在写入流时我应该知道什么时候做这样的事情?
如果有人能帮我解决这两个问题,我们将不胜感激。
答案 0 :(得分:2)
•当我想指定要写入流的字节数时,我是否应该使用write?
是的 - 如果在内存中连续排列的特定数量的字节数据按顺序写入流中,则应使用write
。但有时您可能需要特定数量的字节并需要以另一种方式获取它们,例如将double
的ASCII表示格式化为具有特定的宽度和精度。
其他时候你可能会使用>>
,但这必须是非内置类型的用户定义,并且当它被定义时 - 通常为了更好但是对于你的目的可能更糟 - 它打印任何类设计者选择,包括通过指针或参考和感兴趣的静态数据从对象链接的潜在数据,和/或动态计算的值。它可能会更改数据表示:比如将二进制double
转换为ASCII表示,或者确保网络字节顺序,而不管主机的字节顺序如何。它也可能省略一些对象的数据,例如缓存条目,用于管理但不是逻辑上部分数据的计数器,未填充的数组元素等。
为什么要使用reinterpret_cast到char *?在写入流时,我应该何时知道做类似的事情?
write()
函数签名需要const char*
参数,因此正在进行此转换。只要您无法获得char*
数据,就需要使用强制转换。
强制转换反映了write()
将对象的第一个字节处开始的数据视为8位值的方式,而不考虑数据的实际预制类型。这与能够执行诸如write()
的最后一个字节float
和同一结构中下一个出现的double
的前3个字节之类的事情相关联 - 所有数据边界在reinterpret_cast<>
之后,解释就会丢失。
(当你从输入流中执行read()
个字节时,你实际上必须更加小心......假设你在写入内存时读取构成double
的数据适当地对齐double
,然后尝试将其用作double
,您可能会从CPU获得SIGBUS或类似的对齐异常,或者性能会降低,具体取决于您的系统。)
答案 1 :(得分:1)
basic_ostream::write
及其对应的basic_istream::read
用于在数据流上执行未格式化的I / O.通常,这是原始二进制数据,可能包含也可能不包含可打印的ascii字符。
read
/ write
与<<
,>>
,getline
等其他格式化运算符之间的主要区别在于前者不会对正在处理的数据做出任何假设 - 您可以完全控制从流中读取和写入的字节数。与后者相比,后者可能会跳过空格,丢弃或忽略它们等等。
要回答第二个问题,reinterpret_cast <char *>
可以满足函数签名并一次使用缓冲区一个字节。不要让char
类型欺骗你。使用char
的原因是因为它是语言提供的最小的内置基元类型。或许更好的名称可能是uint8
,表明它实际上是无符号字节类型。