Использование std :: find для поиска символов, считанных из двоичного файла и приведенных к std :: string в std :: vector <string>, создает это непредсказуемое поведение? - PullRequest
0 голосов
/ 06 марта 2019

Извините за длинный заголовок. Я не мог знать, как описать это короткими словами.

Не хотите ли воссоздать проблему, с которой я сталкиваюсь?

Вы можете использовать любой 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 Ответ

4 голосов
/ 06 марта 2019

std::string query(fileData) использует strlen на fileData, чтобы найти его завершающий 0, но не находит его, потому что fileData не заканчивается нулем и продолжает поиск 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());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...