Как правильно вывести шестнадцатеричные данные в файл? - PullRequest
0 голосов
/ 12 июня 2011

Я прочитал о [ostream] << hex << 0x[hex value], но у меня есть несколько вопросов по этому поводу

(1) Я определил свой файловый поток, output, как шестнадцатеричный поток выходного файла, используя output.open("BWhite.bmp",ios::binary);, поскольку я это сделал, делает ли это параметр hex в операции output<< избыточным?

(2) Если у меня есть целочисленное значение, которое я хотел сохранить в файле, и я использовал это:

int i = 0;
output << i;

Буду ли я хранить в младшем или старом порядке?Изменится ли конечность в зависимости от того, на каком компьютере выполняется или компилируется программа?

Зависит ли размер этого значения от компьютера, на котором она запущена?Нужно ли использовать шестнадцатеричный параметр?

(3) Есть ли способ вывести необработанные шестнадцатеричные цифры в файл?Если я хочу, чтобы файл имел шестнадцатеричную цифру 43, что я должен использовать?

output << 0x43 и output << hex << 0x43 оба выводят ASCII 4, затем ASCII 3.

Целью вывода этих шестнадцатеричных цифр является создание заголовка для файла .bmp.

Ответы [ 3 ]

7 голосов
/ 12 июня 2011

Вы говорите

"Есть ли способ вывести необработанные шестнадцатеричные цифры в файл? Если я хочу, чтобы файл имел шестнадцатеричную цифру 43, что я должен использовать?"

«Необработанные шестнадцатеричные цифры» будут зависеть от того, как вы интерпретируете набор битов. Учтите следующее:

 Binary  :    0 1 0 0 1 0 1 0
 Hex     :    4 A
 Octal   :    1 1 2
 Decimal :    7 4
 ASCII   :    J

Все вышеперечисленное представляет одну и ту же числовую величину, но мы интерпретируем ее по-разному.

Таким образом, вам может просто потребоваться сохранить данные в двоичном формате, то есть точную битовую комбинацию, которая представлена ​​числом.

EDIT1

Когда вы открываете файл в текстовом режиме и пишете в нем число, например, когда вы пишете 74 (как в примере выше), он будет сохранен как два символа ASCII '7' и '4'. Чтобы избежать этого, откройте файл в двоичном режиме ios::binary и запишите его с write (). Чек http://courses.cs.vt.edu/~cs2604/fall00/binio.html#write

7 голосов
/ 12 июня 2011

Оператор форматированного вывода << предназначен только для этого: форматированный вывод.Это для строк.

Таким образом, потоковый манипулятор std::hex сообщает потокам выводить числа в виде строк, отформатированных как шестнадцатеричные.

Если вы хотите выводить необработанные двоичные данные, используйте неформатированные выходные функции только , например, basic_ostream::put и basic_ostream::write.

Вы можете вывести int таким образом:

int n = 42;
output.write(&n, sizeof(int));

Порядковый номер этого вывода будет зависеть от архитектуры,Если вы хотите иметь больший контроль, я предлагаю следующее:

int32_t n = 42;
char data[4];
data[0] = static_cast<char>(n & 0xFF);
data[1] = static_cast<char>((n >> 8) & 0xFF);
data[2] = static_cast<char>((n >> 16) & 0xFF);
data[3] = static_cast<char>((n >> 24) & 0xFF);
output.write(data, 4);

В этом примере 32-разрядное целое число будет выводиться как little-endian независимо от порядкового номера платформы.Будьте осторожны, конвертируя это обратно, если char подписано, однако.

3 голосов
/ 12 июня 2011

Целью вывода этих шестнадцатеричных цифр является создание заголовка для файла .bmp.

У вас, кажется, есть большое неправильное представление о том, как работают файлы.

Операторы потока << генерируют текст (удобочитаемый вывод). Формат файла .bmp - это двоичный формат, который не читается человеком (будет, но не очень хорошо, и я бы не стал читать его без инструментов).

Что вы действительно хотите сделать, это сгенерировать двоичный вывод и поместить его в файл:

char   x = 0x43;
output.write(&x, sizeof(x));

Это записывает один байт данных с шестнадцатеричным значением 0x43 в выходной поток. Это двоичное представление, которое вы хотите.

будет ли я храниться в младшем или старом порядке? Изменится ли конечность в зависимости от того, на каком компьютере запущена или скомпилирована программа?

Ни; Вы снова выводите текст (не двоичные данные).

int i = 0;
output.write(reinterpret_cast<char*>(&i), sizeof(i)); // Writes the binary representation of i

Здесь вам нужно беспокоиться о порядке (и размере) целочисленного значения, и это будет зависеть от оборудования, на котором вы запускаете приложение. Для значения 0 не нужно беспокоиться о порядке байтов, но вы должны беспокоиться о размере целого числа.

Я бы добавил некоторые утверждения в мой код, чтобы проверить правильность архитектуры для кода. Тогда пусть люди беспокоятся о том, что их архитектура не соответствует требованиям:

int test = 0x12345678;
assert((sizeof(test) * CHAR_BITS == 32) && "BMP uses 32 byte ints");
assert((((char*)&test)[0] == 0x78) && "BMP uses little endian");

Существует семейство функций, которые помогут вам с порядком байтов и размером.

http://www.gnu.org/s/hello/manual/libc/Byte-Order.html

Функция: uint32_t htonl (uint32_t hostlong)
Эта функция преобразует целое число uint32_t hostlong из порядка байтов хоста в порядок байтов сети.

// Writing to a file
uint32_t hostValue = 0x12345678;
uint32_t network   = htonl(hostValue);
output.write(&network, sizeof(network));

// Reading from a file
uint32_t network;
output.read(&network, sizeof(network);
uint32_t hostValue = ntohl(network);    // convert back to platform specific value.

// Unfortunately the BMP was written with intel in-mind
// and thus all integers are in liitle-endian.
// network bye order (as used by htonl() and family) is big endian.
// So this may not be much us to you.

Последнее. Когда вы открываете файл в двоичном формате output.open("BWhite.bmp",ios::binary), он ничего не делает для потоковой передачи, кроме того, как он обрабатывает end of line sequence. Когда файл находится в двоичном формате, вывод не изменяется (то, что вы помещаете в поток, это то, что записывается в файл). Если вы оставите поток в текстовом режиме, то символы '\ n' преобразуются в конец строки (специфический для ОС набор символов, определяющий конец строки). Поскольку вы пишете двоичный файл, вы определенно не хотите никакого вмешательства в символы, которые вы пишете, поэтому двоичный файл является правильным форматом. Но это не влияет на другие операции, выполняемые в потоке.

...