2017-02-23 90 views
1

鉴于以下代码:是定义的流实现的默认模式吗?

std::ofstream stream("somefile"); 

if (!stream) 
{ 
    return 1; 
} 

当调用.WRITE(....)和使用STDC++的libC++流处于二进制模式(std::ios::binary)。

使用当MSVC(2015/2017RC1)它似乎是在文本模式或奇怪的东西,因为生成的文件比实际写入大。然而。

但是,如果我明确地设置模式std::ios::binary MSVC的行为类似于前面提到的其他标准库的std::ofstream实现。


示例代码:

expect: 32 
file size: 33 

输出,用于当与libc的运行++上面的代码,STDC++::

expect: 32 
file size: 32 

#include <vector> 
#include <cstdio> 
#include <fstream> 

std::size_t fsz(const char* filename) { 
    std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary); 
    return static_cast<std::size_t>(in.tellg()); 
} 

int main() { 
    std::ofstream stream("filename"); 

    if (!stream) 
     return 1; 

    std::vector<unsigned long long int> v = {0x6F1DA2C6AC0E0EA6, 0x42928C47B18C31A2, 0x95E20A7699DC156A, 0x19F9C94F27FFDBD0}; 

    stream.write(reinterpret_cast<const char*>(v.data()),v.size() * sizeof(unsigned long long int)); 

    stream.close(); 

    printf("expect: %d\n", v.size() * sizeof(unsigned long long int)); 
    printf("file size: %d\n", fsz("filename")); 

    return 0; 
} 

输出用于上述代码时用MSVC运行

区别可以得到m这取决于写入的数据量和数据的内容。

最后我的问题仍然是一样的,是不确定的还是不明确的行为?


将上述向量更改为以下内容使得该示例对于发生了什么更为明显。

std::vector<unsigned long long int> v = {0x0A0A0A0A0A0A0A0A, 0x0A0A0A0A0A0A0A0A, 0x0A0A0A0A0A0A0A0A, 0x0A0A0A0A0A0A0A0A}; 
+0

请描述_exactly_你看到了什么。多大?该文件包含什么内容?你的'write()'调用在哪里?出示[MCVE]。 –

+0

@LightnessRacesinOrbit我已经添加了一个例子。 –

回答

3

流构造函数使用的默认模式是ios_base::out。由于没有明确的text模式标志,这意味着流以文本模式打开。文本模式仅对Windows系统有影响,它将\n字符转换为CR/LF对。在POSIX系统上它不起作用,文本和二进制模式在这些系统上是同义词。

+0

0x0A字节转换为0x0D0A,因此在矢量的第3个元素中,窗口下的0x0A字节被“加倍”。 –

+0

所以@Torrie你是如何得出以下结论的? _“当调用.write(....)并使用stdC++和libC++时,流处于二进制模式('std :: ios :: binary')。”_这似乎不是真的。 –

3

当我运行使用g++libstdc++ Windows代码,我得到以下结果:

expect: 32 
file size: 33 

所以问题不在于具体的编译器,而是OS具体。

虽然C++使用单个字符\n来表示在一个串结束的行,Windows使用两个字节0x0D0x0A用于在文件结束的行。这意味着如果您在文本模式下将字符串写入文件,则使用这两个字节写入所有出现的单个字符\n。这就是为什么你会在你的例子的文件大小中获得额外的字节。

+0

字符或字符串文字中的''\ n''在每个** C和C++程序结束一行。在Windows下的**文件**中,行的结尾由两个字节表示,值为“0x0D”和“0x0A”。巧合的是,这些值恰好与编译器在**源文件**中看到“\ r”和“\ n”时使用的值相同。在''\ r''或''\ n''与编译代码或文本文件中的任何特定值之间没有**必需的**连接。 –

+0

@PeteBecker谢谢,我更新了我的答案。 – pschill

+0

干得好! (忽略填充) –