我使用以下代码(取自https://codereview.stackexchange.com/questions/22901/reading-all-bytes-from-a-file)在C ++中有效地将文件读入数组:
static std::vector<char> ReadAllBytes(char const* filename)
{
std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
std::ifstream::pos_type pos = ifs.tellg();
std::vector<char> result(pos);
ifs.seekg(0, std::ios::beg);
ifs.read(&result[0], pos);
for (unsigned int i = 0; i < result.size(); i++)
if (result.at(i) != 0)
return result; // [1]
//if (!ifs.good()) // Commenting out changes contents of result
// return result; // [2] // Commenting out changes contents of result
return result; // [3]
}
一切运行完美,[1]处的断点触发并且函数返回数据(循环仅用于调试,因为我已经获得了0填充的返回值,应该保存数据)。但是,只要我在[2]处删除If-Statement,断点[3]就会触发并且数组为空(大小正确,但数组中填充了零)。
从未执行的代码如何实际改变函数的行为?我认为它可能与堆栈布局有关,而且我将流和数据作为局部变量保存,但在堆上手动创建它们会导致完全相同的情况。
你觉得我完全不知所措。我以前从未见过这样的东西。怎么可能呢?
PS:我应该补充一点,文件内容是二进制的,文件大小约为32 MB。
答案 0 :(得分:1)
您是否正在使用优化进行编译(发布模式)?如果是这样,那么如果我不得不猜测,我会说它正在重新排序您的代码。首先,请注意read
之后的所有代码都不重要。所有它正在做的是在所有情况下返回result
并且不更改数组中的任何内容。许多函数都可以内联,这意味着一个好的编译器可以知道这一点并删除所有代码。
这样可以很容易地解释断点行为。但添加if (!ifs.good())
并将数据设为空 - 这很难解释。也许关于read
函数的这一点可以提供洞察力:
在内部,该函数首先构造一个sentry对象(noskipws设置为true)来访问输入序列。然后(如果好),它从其关联的流缓冲区对象中提取字符,就像调用其成员函数sbumpc或sgetc一样,最后在返回之前销毁sentry对象。
请注意,read包含对good()
的检查,这意味着编译器可能正在组合good()
的两个检查(内联后read
中的一个检查,以及在你的代码中)并使用它完全跳过读取(?)。这似乎不太可能,但也许它指出了你的调试方向。
我会说我在使用优化器之前已经看过这个问题了。不是ifstreams的这个特定问题,而是添加看似未使用的代码的更普遍的问题改变了行为。原因总是最终可以自由地重新排序不会改变结果的代码。
答案 1 :(得分:0)
对于任何想知道的人:我无法确定C ++的奇怪行为的原因 - 编译器(也许我确实发现了一个错误?)。
然而,只要以块的形式读取文件,一切都可以正常运行。为方便起见,我会发布代码:
static bool ReadAllBytes(char const* filename, char** result, size_t* size)
{
const size_t BUFFER_SIZE = 32;
std::ifstream ifs(filename, std::ios::binary | std::ios::ate | std::ios::in);
*size = ifs.tellg();
*result = new char[*size];
ifs.seekg(0, std::ios::beg);
size_t operations = *size / BUFFER_SIZE;
size_t chunks = 0;
for (; chunks < operations && ifs.good(); chunks++)
ifs.read(*result + chunks * BUFFER_SIZE, BUFFER_SIZE);
if (ifs.good() && *size % BUFFER_SIZE > 0)
ifs.read(*result + chunks * BUFFER_SIZE, *size % BUFFER_SIZE);
return (ifs.good());
}