У меня есть простой текстовый файл, и я хочу прочитать его как шестнадцатеричный. Например, следующий текст находится в текстовом файле "315c4e", теперь это фактически три байта, я хочу сохранить их в отдельных переменных (или в массиве, который когда-либо возможен). Например, первая переменная say uint8_t v1 должна содержать 31, другими словами, эта переменная должна иметь значение 00110001 (которое равно 31 в шестнадцатеричном формате).
Я занимаюсь криптографическим заданием в своем колледже, и мне приходилось считывать значения из текстовых файлов, содержащих шестнадцатеричные шифрованные тексты.
Нормальный setw
и setprecision
не будет ограничивать объем ввода для чтения двух символов, так что- то вроде этого:
infile >> std::setw(2) >> setprecision(2) >> std::hex >> ch;
... просто не сработает. В этом случае, вероятно, примерно так же просто, как и все, чтобы просто прочитать 2-символьную строку и сделать преобразование самостоятельно:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <ctype.h>
unsigned char hstouc(std::string const &in) {
static const std::string v{ "0123456789ABCDEF" };
return v.find(toupper(in[0])) * 16 + v.find(toupper(in[1]));
}
int main() {
std::istringstream in{ "315c4e" };
std::vector<unsigned char> vals;
std::string temp;
while (in >> std::setw(2) >> temp)
vals.push_back(hstouc(temp));
for (unsigned v : vals)
std::cout << v << "\t";
}
Если ваш вход сгенерирован машиной, этого, вероятно, будет достаточно. Если он может быть отредактирован вручную (или что-то еще, что может привести к некорректному вводу), вам, вероятно, потребуется/захочет добавить некоторую проверку ошибок в процедуру преобразования. Кроме того, вы можете использовать что-то вроде strtoul
, которое уже выполняет такую проверку, а затем приводит результат к unsigned char
.
Если вы хотите прочитать кортежи из 3 байтов (6 символов), разделенные пробелами:
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
struct ToHex
{
typedef std::uint8_t byte;
typedef std::istream::traits_type traits;
byte& value;
ToHex(byte& value)
: value(value)
{}
void read(std::istream& stream) const {
byte b[2];
for(unsigned i = 0; i < 2; ++i) {
traits::char_type ch = stream.get();
if('0' <= ch && ch <= '9') b[i] = ch - '0';
else if('a' <= ch && ch <= 'f') b[i] = ch - 'a' + 10;
else if('A' <= ch && ch <= 'F') b[i] = ch - 'A' + 10;
else {
if(ch != traits::eof())
stream.putback(ch);
stream.setstate(std::ios_base::failbit);
}
}
value = b[0] * 16 + b[1]; // Rubbish if an extraction failed
}
};
inline ToHex to_hex(ToHex::byte& value) {
return ToHex(value);
}
inline std::istream& operator >> (std::istream& stream, const ToHex& value) {
value.read(stream);
return stream;
}
int main() {
std::istringstream input(""
"315c4e\n"
"010c0e\n"
"Failure");
ToHex::byte a[3];
input >> std::ws;
while(input && ! input.eof()) {
for(unsigned i = 0; i < 3; ++i) {
input >> to_hex(a[i]);
}
if(input) {
for(unsigned i = 0; i < 3; ++i)
std::cout << std::hex << std::setw(2) << std::setfill('0') << (unsigned)a[i];
std::cout << '\n';
input >> std::ws;
}
}
if(input.fail()) {
std::cerr << "Failure\n";
}
}
Этот вопрос дал мне идею следующей функции, и я не могу устоять, чтобы опубликовать ее здесь. Кстати, есть стандартная функция делает то же самое, как это atob
?
int atob(unsigned char c) {
static char x[256];
int i;
if (x[0]==0) {
for(i=0;i<256;i++) x[i] = -1;
for(i=0;i<10;i++) x[i+'0'] = i;
for(i=0;i<6;i++) x[i+'a']= x[i+'A'] = i+10;
}
return(x[c]);
}
int main() {
FILE *ff;
int hex, c1, c2;
ff = fopen("test.txt", "r");
for(;;) {
c1 = fgetc(ff);
c2 = fgetc(ff);
if (c2 == EOF) break;
hex = atob(c1)*16 + atob(c2);
printf("0x%02x ", hex);
}
fclose(ff);
}
sscanf(buf,"%x",...);
в теме.