使用std :: find查找从二进制文件读取的字符并将其转换为std :: vector <string>中的std :: string会创建这种不可预测的行为吗?

时间:2019-03-06 15:00:24

标签: c++ c++11

抱歉,标题太长了。我不知道如何用简短的词来形容。

您是否愿意重现我遇到的问题?

您可以使用任何wav文件进行读取。

我正在尝试在wav文件中查询块,这是代码的简化版本,但是我认为如果有问题,可能足以重新创建。

我使用的是Mac,并使用g++ -std=c++11进行编译。

当我运行此代码并且不包括行std::cout << query << std::endl;时,std::find(chunk_types.begin(), chunk_types.end(), query) != chunk_types.end()在所有迭代中均返回0。但是我知道二进制文件包含其中一些块。如果我加入这行,那么它可以正常工作,但是那也是不可预测的,可以说有时候它可以正常工作。

我有点困惑,我在这里做错什么了吗?

#include <fstream>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector> 

int main(){    

    std::vector<std::string> chunk_types{
    "RIFF","WAVE","JUNK","fmt ","data","bext",
    "cue ","LIST","minf","elm1",
    "slnt","fact","plst","labl","note",
    "adtl","ltxt","file"};

    std::streampos fileSize;
    std::ifstream file(/* file path here */, std::ios::binary);
    file.seekg(0, std::ios::beg);

    char fileData[4];

    for(int i{0};i<100;i+=4){ //100 is an arbitrary number

        file.seekg(i);
        file.read((char*) &fileData[0], 4);
        std::string query(fileData);

        std::cout << query << std::endl;

        /* if i put this std::cout here, it works or else std::find always returns 0 */


        if( std::find(chunk_types.begin(), chunk_types.end(), query) != chunk_types.end() ){ 
           std::cout << "found " + query << std::endl; 
        } 

    }

return 0;

}

1 个答案:

答案 0 :(得分:4)

std::string query(fileData)strlen上使用fileData来查找其终止0,但未找到一个,因为fileData并不以0结尾,并继续在0上搜索0。堆栈,直到找到它或在堆栈末尾击中不可访问的内存并导致SIGSEGV

此外,file.read读取的符号少于预期的符号,必须使用gcount提取上次读取的实际字符数:

修正:

file.read(fileData, sizeof fileData);
auto len = file.gcount();
std::string query(fileData, len);

一种更有效的解决方案是直接读入std::string并继续重用它以避免内存分配(如果没有短字符串优化)和复制:

std::string query;
// ...
    constexpr int LENGTH = 4;
    query.resize(LENGTH);
    file.read(&query[0], LENGTH);
    query.resize(file.gcount());