2017-02-23 201 views
1

Учитывая следующий код:Определен ли режим по умолчанию для реализации потока?

std::ofstream stream("somefile"); 

if (!stream) 
{ 
    return 1; 
} 

При вызове .WRITE (....) и использование STDC++ и LibC++ поток в двоичном режиме (std::ios::binary).

Однако при использовании MSVC(2015/2017RC1) это, кажется, в текстовом режиме или что-то странное, потому что результирующий файл больше, чем то, что на самом деле написано.

Но если я явно задал режим std::ios::binary MSVC ведет себя аналогично реализациям других стандартных библиотек, упомянутых ранее.


Пример кода:

#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:

expect: 32 
file size: 33 

выход для приведенного выше кода при запуске с LIBC++, STDC++:

expect: 32 
file size: 32 

Разница может достигать m uch больше, это зависит от того, сколько данных записано и содержимое данных.

В конце мой вопрос остается тем же, не определено ли это неопределенное или неуказанное поведение?


изменение вышеуказанного вектора следующим образом делает пример более очевидным в отношении того, что происходит.

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, поэтому в третьем элементе вектора байт 0x0A под окнами «удваивается». –

+0

Итак, @Torrie, как вы пришли к следующему выводу? _ "При вызове .write (....) и использовании stdC++ и libC++ поток находится в двоичном режиме (' std :: ios :: binary'). "_ Это не похоже на правду. –

3

Когда я запускаю свой код на окна с помощью g++ и libstdc++, я получаю следующий результат:

expect: 32 
file size: 33 

Так что проблема не конкретного компилятора, а ОС конкретные.

В то время как C++ использует один символ \n для представления строки, заканчивающейся строкой, Windows использует два байта 0x0D и 0x0A для строки, заканчивающейся в файле. Это означает, что если вы пишете строку в файл в текстовом режиме, все вхождения одного символа \n записываются с использованием этих двух байтов. Вот почему вы получаете дополнительные байты в размере файла ваших примеров.

+0

'' \ n'' символа или строкового литерала заканчивает строку в ** каждой ** программе C и C++. В ** файле ** под Windows конец строки представлен двумя байтами со значениями «0x0D» и «0x0A». По совпадению эти значения совпадают с теми значениями, которые используются компиляторами, когда они видят '' \ r'' и '' \ n' 'в ** исходном файле **. Не существует ** обязательной ** связи между '' \ r'' или '' \ n'' и любым конкретным значением в скомпилированном коде или в текстовом файле. –

+0

@PeteBecker Спасибо, я обновил свой ответ. – pschill

+0

Молодцы! (игнорировать заполнение) –