为什么ostream :: write()在C++中需要'const char_type*'而不是'const void*'?

Mr.*_*Ree 20 c++ file fwrite void ofstream

fwrite()C中的函数const void *restrict buffer用作第一个参数,因此您可以直接将指针struct作为第一个参数传递给您.
http://en.cppreference.com/w/c/io/fwrite
例如fwrite(&someStruct, sizeof(someStruct), 1, file);

但在C++中,ostream::write()需求const char_type*会迫使您使用reinterpret_cast.(在Visual Studio 2013中,它是const char*.)
http://en.cppreference.com/w/cpp/io/basic_ostream/write
egfile.write(reinterpret_cast<char*>(&someStruct), sizeof(someStruct));

几乎在所有情况下,要写入文件的二进制数据都不是char数组,那么为什么标准更喜欢看起来更复杂的样式呢?

PS
1.实际上我write()ofstreamwith ios::binary模式下使用了这个方法,但根据引用,它继承了ofstream.所以我ostream::write()在上面使用.
2.如果要打印字符流,可以使用operator<<().是不是write()为编写原始数据而设计的方法?
3.如果write()不是编写二进制数据的方法,那么在标准中执行此操作的方法是什么?(尽管由于不同平台上的各种内存对齐策略,这可能会影响代码的可移植性)

Ton*_*roy 13

将其描述为C与C++之类的东西是误导性的.C++提供的std::fwrite(const void*, ...)就像C一样.C++选择更具防御性的是std::iostream版本.

"几乎在所有情况下,要写入文件的二进制数据都不是char数组"

这是值得商榷的.在C++中,在I/O中添加一个间接级别并不少见,因此将对象流式传输或序列化为方便的 - 并且可能是可移植的(例如,字节序标准化,没有或使用标准化结构填充) - 表示,然后反序列化/重新阅读时解析.逻辑通常针对所涉及的各个对象进行本地化,使得顶级对象不需要知道其成员的存储器布局的细节.序列化和流式传输往往在字节级别被认为/缓冲等 - 更好地适应字符缓冲区,read()write()返回当前可以传输的许多字符 - 再次在字符而不是对象级别 - 所以它不是很非常有效地假装,否则你将无所事事地恢复部分成功的I/O操作.

天真的原始二进制写入/读取有点危险,因为它们不处理这些问题,因此使用这些函数稍微有点困难,reinterpret_cast<>有点代码味道/警告可能是一件好事.

也就是说,C++使用的一个不幸的方面char*是,它可能会鼓励一些程序员首先读取一个字符数组,然后使用不适当的强制转换来"重新解释"动态数据 - 就像一个int*针对字符缓冲区的方式可能没有适当调整.

如果要打印字符流,可以使用operator<<().是不是write()为编写原始数据而设计的方法?

打印字符流operator<<()是有问题的,因为唯一相关的重载需要一个const char*并且需要一个'\0'/ NUL终止的缓冲区.如果你想在输出中打印一个或多个NUL,那就没用了.此外,当以较长的字符缓冲区开始时,operator<<通常会出现笨拙,冗长和容易出错的问题,需要NUL在流式传输中进行交换,并且有时会出现重要的性能和/或内存使用问题,例如在编写某些时 - 但不是end - 一个长字符串文字,你不能交换NUL,或者从其他不应该看到NUL的线程读取字符缓冲区.

提供的std::ostream::write(p, n)功能可以避免这些问题,让您准确指定要打印的数量.


Sin*_*all 10

char_type并不完全是char *,它是流的模板参数,表示流的字符类型:

template<typename _CharT, typename _Traits>
class basic_ostream : virtual public basic_ios<_CharT, _Traits>
{
public:
    // Types (inherited from basic_ios):
    typedef _CharT                  char_type;
    <...>
Run Code Online (Sandbox Code Playgroud)

而且std::ostream只是char实例化:

typedef basic_ostream<char> ostream;
Run Code Online (Sandbox Code Playgroud)

  • 这回答了这个问题吗? (4认同)