Как читать шестнадцатеричные значения в целое число с помощью fstream (С++)

Я пытаюсь прочитать шестнадцатеричную строку с прямым порядком байтов из двоичного файла и поместить это значение в целое число для работы с ним. Когда я пытаюсь читать, вместо числа я получаю символы ascii. Я пробовал литье и atoi, и ничего не работает. Как лучше всего использовать fstream для чтения шестнадцатеричной строки в целое число из файла?

Это по сути моя программа:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(int argc, char* argv[]) {
    fstream input;
    fstream output;
    char cbuffer[4];
    char revbuffer[8];

    input.open(argv[1], fstream::binary | fstream::in);
    output.open("output.txt", ios::out | ios::app);
    input.seekg(16, input.beg);
    input.read(cbuffer, 4);

    cout << sizeof(revbuffer) << endl;
    cout << cbuffer[0] << cbuffer[1] << cbuffer[2] << cbuffer[3] << endl;
}

person Kasper    schedule 19.11.2018    source источник
comment
действительно ли значение хранится в файле в виде шестнадцатеричной строки? Вы упомянули порядок байтов и прочитали 4 символа из файла, поэтому шестнадцатеричная строка кажется маловероятной.   -  person Ted Lyngmo    schedule 19.11.2018
comment
Может быть, не тогда, я действительно не знаю, как это назвать. Я довольно новичок в программировании. Значение имеет смещение 0x10 и выглядит примерно так [в шестнадцатеричном формате] 00 92 f8 03. Число должно читаться как 0x03f89200.   -  person Kasper    schedule 20.11.2018


Ответы (1)


Если это целочисленное значение, хранящееся в двоичном формате, я предполагаю, что это либо int32_t, либо uint32_t. Поскольку вы упомянули, что значение хранится в порядке байтов с прямым порядком байтов, я думаю, вы хотите убедиться, что хост, на котором запущена ваша программа, преобразует его (если это необходимо). C++20 имеет std::endian. Если это вам недоступно, обычно есть макросы для определения порядка байтов во время компиляции, которые вы можете использовать вместо std::endian тестов, которые я использовал. Я предположил, что значение uint32_t ниже.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <type_traits> // std::endian

// little endian unsigned 32 bit integer to host byte order
inline uint32_t Le32toh(uint32_t le) {
    #if __cplusplus <= 201703L
    // run-time check
    static constexpr uint16_t endian = 1;
    if(*reinterpret_cast<const uint8_t*>(&endian)==1) return le;
    #else
    // compile-time check
    static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big);
    if constexpr (std::endian::native == std::endian::little) return le;
    #endif

    const uint8_t* c=reinterpret_cast<const uint8_t*>(&le);
    return // little-to-big endian conversion
        (static_cast<uint32_t>(c[0])<<24) |
        (static_cast<uint32_t>(c[1])<<16) |
        (static_cast<uint32_t>(c[2])<<8) |
        (static_cast<uint32_t>(c[3]));

    return le;
}


int main(int argc, char* argv[]) {
    std::vector<std::string> args(argv+1, argv+argc);

    std::fstream output("output.txt", std::ios::out | std::ios::app);

    uint32_t cbuffer;

    for(const auto& file : args) {
        std::fstream input(file, std::fstream::binary | std::fstream::in);
        input.seekg(16, input.beg);
        // read directly into the varibles memory
        input.read(reinterpret_cast<char*>(&cbuffer), 4);
        // output the value unconverted
        std::cout << std::hex << cbuffer << "\n";
        // convert if needed
        cbuffer = Le32toh(cbuffer);
        // output the value converted
        std::cout << std::hex << cbuffer << "\n";
    }
}
person Ted Lyngmo    schedule 19.11.2018
comment
Спасибо за ответ. Я получаю сообщение об ошибке: 'std::endian' не был объявлен. Но только с main теперь я могу прочитать значение как int. Спасибо большое! - person Kasper; 20.11.2018
comment
Большой! Да, std::endian - это функция С++ 20, поэтому, чтобы иметь возможность делать что-то подобное во время компиляции в С++ 17 и ранее, вам придется прибегнуть к какому-то нестандартному макросу с порядком байтов или выполнить проверку во время выполнения. Я тоже добавлю. - person Ted Lyngmo; 20.11.2018