C ++未执行的代码会改变函数行为吗?

时间:2013-11-20 13:50:03

标签: c++ visual-c++

我使用以下代码(取自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。

2 个答案:

答案 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());
}