Влияет ли порядок байтов на запись нечетного числа байтов? - PullRequest
0 голосов
/ 08 января 2019

Представьте, что у вас есть uint64_t bytes, и вы знаете, что вам нужно всего 7 байтов, потому что целые числа, которые вы храните, не превысят ограничение в 7 байтов.

При записи файла вы можете сделать что-то вроде

std::ofstream fout(fileName); fout.write((char *)&bytes, 7);

только для записи 7 байтов.

Вопрос, который я пытаюсь выяснить, заключается в том, влияет ли порядок в системе на байты, которые записываются в файл. Я знаю, что порядок байтов влияет на порядок записи байтов, но влияет ли он также на то, какие байты записываются? (Только для случая, когда вы пишете меньше байтов, чем обычно имеет целое число.)

Например, в системе с прямым порядком байтов первые 7 байтов записываются в файл, начиная с LSB. В системе с прямым порядком байтов, что записывается в файл?

Или, иначе говоря, в системе с прямым порядком байтов MSB (8-й байт) не записывается в файл. Можем ли мы ожидать того же поведения в системе с прямым порядком байтов?

Ответы [ 3 ]

0 голосов
/ 08 января 2019
uint64_t bytes = ...;
fout.write((char *)&bytes, 7);

Это будет писать ровно 7 байтов, начиная с адреса & байтов. Между системами LE и BE есть различие в том, как расположены восемь байтов в памяти, хотя (предположим, переменная расположена по адресу 0xff00):

            0xff00  0xff01  0xff02  0xff03  0xff04  0xff05  0xff06  0xff07
LE: [byte 0 (LSB!)][byte 1][byte 2][byte 3][byte 4][byte 5][byte 6][byte 7 (MSB)]
BE: [byte 7 (MSB!)][byte 6][byte 5][byte 4][byte 3][byte 2][byte 1][byte 0 (LSB)]

Начальный адрес (0xff00) не изменится, если приведен к типу char *, и вы распечатаете байт точно по этому адресу плюс следующие шесть следующих & ndash; в обоих случаях (LE и BE) адрес 0xff07 печататься не будет. Теперь, если вы посмотрите на мою таблицу памяти выше, должно быть очевидно, что в системе BE вы теряете LSB при сохранении MSB, который не несет информацию ...

В системе BE вы могли бы написать fout.write((char *)&bytes + 1, 7);. Имейте в виду, однако, что это все еще оставляет проблему переносимости:

fout.write((char *)&bytes + isBE(), 7);
//                           ^ giving true/false, i. e. 1 or 0
// (such function/test existing is an assumption!)

Таким образом, данные, записанные системой BE, будут неправильно интерпретированы системой LE при обратном чтении и наоборот. Безопасной версией будет разложение каждого байта, как это сделал geza в своем ответе . Чтобы избежать нескольких системных вызовов, вы можете вместо этого разложить значения в массив и распечатать его.

Если в linux / BSD есть хорошая альтернатива , тоже:

bytes = htole64(bytes); // will likely result in a no-op on LE system...
fout.write((char *)&bytes, 7);
0 голосов
/ 08 января 2019

Вопрос, который я пытаюсь выяснить, заключается в том, влияет ли порядковый номер системы на байты, записываемые в файл.

Да, это влияет на запись байтов в файл.

Например, в системе с прямым порядком байтов первые 7 байтов записываются в файл, начиная с LSB. В системе с прямым порядком байтов, что записывается в файл?

Первые 7 байтов записываются в файл. Но на этот раз, начиная с MSB. Итак, в конце самый младший байт - это , а не , записанный в файле, потому что в системах с прямым порядком байтов последний байт является младшим байтом.

Итак, это не то, что вы хотели, потому что вы теряете информацию.

Простое решение - преобразовать uint64_t в младший порядок и записать преобразованное значение. Или просто запишите значение побайтово, как это сделала бы система с прямым порядком байтов:

uint64_t x = ...;

write_byte(uint8_t(x));
write_byte(uint8_t(x>>8));
write_byte(uint8_t(x>>16));
// you get the idea how to write the remaining bytes
0 голосов
/ 08 января 2019

Endianess влияет только на то, как (16, 32, 64) int написано. Если вы пишете байтов , (как в вашем случае) они будут записаны в том же порядке, в котором вы это делаете.

Например, этот тип письма будет зависеть от порядка байтов:

std::ofstream fout(fileName);
int i = 67;
fout.write((char *)&i, sizeof(int));
...