GCC和MSVC之间的文件输出不一致

时间:2016-06-18 23:19:54

标签: c++ gcc visual-c++

考虑以下类,这是一个简单的文件加载类,用于在构造期间通过将数据加载到内存中来处理小文本文件。

# first check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
  echo "The time program does not exist on this system."
  exit 1
fi

# invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt

通过#include <fstream> #include <ostream> #include <stdexcept> #include <string> #include <vector> class file_loader { public: /** * \brief Constructs a file_loader instance using a given filename. Caches the file contents * into the internal cached storage container. * * \param _filename Name/directory of file to load. * \param _max_line_length Optional, approximate maximum length of file lines. */ file_loader(const std::string& _filename, std::size_t _max_line_length = static_cast<std::size_t>(256)) : fs(_filename), filename(_filename) { cache_contents(_max_line_length); } /** * \brief Deleted copy construction, copy constructing is forbidden. */ file_loader(const file_loader& _other) = delete; /** * \brief Move constructor, moves a given file_loader instance to this leaving the * parameterised instance in a valid but unspecified state. * * \param _other rvalue reference to a file_loader instance to move. */ file_loader(file_loader&& _other) : fs(std::move(_other.fs)), filename(std::move(_other.filename)), cached_contents_vec(std::move(_other.cached_contents_vec)) { } /** * \brief Writes all changes made to the internal cached storage to the * filestream, overwriting the current contents of the file. */ void write_changes() { fs.close(); fs.open(filename); fs.clear(); write_cache(); } /** * \brief Reads a given line of the internal cached storage. This internal * store is guaranteed to always be up to date, no call to write_changes * is required to maintain consistency. * * \param _n Line number to read. * \return const reference to std::string instance given by _n'th line. * \throws Throws std::out_of_range exception if _n exceeds lines in internal cached storage. */ const std::string& read_line(std::size_t _n) const { if (_n >= cached_contents_vec.size()) throw std::out_of_range("File: " + filename + " does not have " + std::to_string(_n) + " lines."); return cached_contents_vec[_n]; } /** * \brief Overwrites a given line of the internal cached storage such that * the next call to write_changes will update the file contents. * * \param _n Line number to overwrite. * \param _str std::string instance to overwrite current line contents with. * \throws Throws std::out_of_range exception if _n exceeds lines in internal cached storage. */ void overwrite_line(std::size_t _n, const std::string& _str) { if (_n >= cached_contents_vec.size()) throw std::out_of_range("File: " + filename + " does not have " + std::to_string(_n) + " lines."); cached_contents_vec[_n] = _str; } /** * \brief Erases a given line of the internal cached storage such that * the next call to write_changes will update the file contents. * * \param _n Line number to erase. * \return Iterator to next valid position in internal cached storage container. */ auto erase_line(std::size_t _n) { return cached_contents_vec.erase(cached_contents_vec.begin()+_n); } /** * \brief Deleted copy assignment operator, copy assignment is forbidden. */ file_loader& operator=(const file_loader& _other) = delete; /** * \brief Move assignment operator, uses move-semantics to move the parameterised * file_loader instance to this. Instance being moved is left in a * valid but unspecified state. * * \param _other rvalue reference to file_loader instance. */ file_loader& operator=(file_loader&& _other) { // check for self-assignment if (this != &_other) { fs = std::move(_other.fs); filename = std::move(_other.filename); cached_contents_vec = std::move(_other.cached_contents_vec); } return *this; } private: std::fstream fs; std::string filename; std::vector<std::string> cached_contents_vec; // internal cached storage container /** * \brief Caches contents of files into the internal cached storage container. * * \param _max_line_length Approximate maximum line length of the file, used for performance improvements. */ void cache_contents(std::size_t _max_line_length) { std::string line_str; // reserve space for performance line_str.reserve(_max_line_length); while (std::getline(fs, line_str)) { cached_contents_vec.push_back(line_str); } } /** * \brief Convenience method for writing a std::vector<std::string> to an std::ostream instance. * * \param _os Instance of std::ostream. * \param _vec Instance of std::vector<std::string> to write to _os. * \return Reference to _os modified with data of _vec. */ void write_cache() { for (const auto& x : cached_contents_vec) { fs << x << "\n"; } } }; GCC (6.1.0)执行时,使用此类似乎会产生不同的结果。假设我有以下文本文件(MSVC (2015)):

test.txt

以及以下cheese ham eggs beef bacon

main

int main(void) { file_loader fl("test.txt"); fl.overwrite_line(3, "chicken"); fl.write_changes(); } 中,它会产生我预期的结果:

MSVC

然而在cheese ham eggs chicken bacon 我得到:

GCC (6.1.0)

换句话说,后者似乎&#34;连接&#34;将覆盖的行和下面的行放入cheese ham eggs chickenbacon 的单个条目中,而前者将条目分开(因为在这种情况下它们应该是我所知道的。)

这里有什么想法吗?我还要提一下,在cached_contents_vec中,MSVC不要求此方法中的两个初始行覆盖以前的文件内容而GCC会这样做。

1 个答案:

答案 0 :(得分:2)

正如@IgorTandetnik评论的那样,这里的问题是GCC产生Unix风格的线端,而MSVC产生基于Windows的线端。在简单的文本编辑器(如记事本)中查看输出时,GCC的Unix风格输出不会被视为行尾指示符,而在更好的情况下打开时会被视为行末指示符。编辑器(例如记事本++)在两种情况下都正确地处理了相同的输出。