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

时间:2015-02-17 09:12:26

标签: c++ file fwrite void ofstream

C中的fwrite()函数使用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
例如file.write(reinterpret_cast<char*>(&someStruct), sizeof(someStruct));

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

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

4 个答案:

答案 0 :(得分:13)

将此作为C vs C ++的描述是误导性的。 C ++提供std::fwrite(const void*, ...)就像C一样.C ++选择更具防御性的是std::iostream版本。

  

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

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

原始的二进制写入/读取天真地有点危险,因为他们不处理这些问题所以使用{{1}这些函数的使用可能会稍微好一点。有点代码味道/警告。

尽管如此,C ++使用reinterpret_cast<>的一个不幸的方面是它可能会鼓励一些程序员首先读取一个字符数组,然后使用不适当的强制转换来重新解释&#34;即时数据 - 就像char*一样,可能无法正确对齐字符缓冲区。

  

如果要打印字符流,可以使用int*。用于编写原始数据的Isn&t operator<<()方法?

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

提供的NUL功能可以避免这些问题,让您准确指定要打印的内容。

答案 1 :(得分: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;
    <...>

std::ostream只是char实例化:

typedef basic_ostream<char> ostream;

答案 2 :(得分:1)

在C / C ++中,char是表示字节的数据类型,因此char[] 是二进制数据的自然数据类型。

我认为,你的问题更好地针对这样一个事实:C / C ++并不是为#34; bytes&#34;而设计的。和&#34;字符&#34;,而不是流库的设计。

答案 3 :(得分:-3)

REE,

在cplusplus.com网站上,ostream::write的签名是:

ostream& write (const char* s, streamsize n);

我刚刚在VS2013上查了一下,你可以轻松写一下:

std::ofstream outfile("new.txt", std::ofstream::binary);
char buffer[] = "This is a string";
outfile.write(buffer, strlen(buffer));