Big Endian и Little Endian для файлов в C ++ - PullRequest
4 голосов
/ 29 января 2010

Я пытаюсь написать некоторый независимый от процессора код для записи файлов с прямым порядком байтов. У меня есть пример кода ниже, и я не могу понять, почему он не работает. Все, что он должен сделать, это позволить байту хранить каждый байт данных один за другим в порядке с прямым порядком байтов. В моей настоящей программе я бы тогда записал отдельный байт в файл, чтобы получить одинаковый порядок байтов в файле независимо от архитектуры процессора.

#include <iostream>

int main (int argc, char * const argv[]) {
 long data = 0x12345678;
 long bitmask = (0xFF << (sizeof(long) - 1) * 8);
 char byte = 0;

    for(long i = 0; i < sizeof(long); i++) {
  byte = data & bitmask;
  data <<= 8;
 }
    return 0;
}

По какой-то причине байт всегда имеет значение 0. Это меня смущает, я смотрю на отладчик и вижу это:

data = 00010010001101000101011001111000 битовая маска = 11111111000000000000000000000000

Я бы подумал, что data & mask даст 00010010, но он просто делает байт 00000000 каждый раз! Как его можно? Я написал некоторый код для порядка с прямым порядком байтов, и это прекрасно работает, см. Ниже:

#include <iostream>

int main (int argc, char * const argv[]) {
 long data = 0x12345678;
 long bitmask = 0xFF;
 char byte = 0;

    for(long i = 0; i < sizeof(long); i++) {
  byte = data & bitmask;
  data >>= 8;
 }
    return 0;
}

Почему порядок с прямым порядком байтов работает, а порядок с прямым порядком нет? Спасибо за любую помощь: -)

Ответы [ 4 ]

6 голосов
/ 29 января 2010

Для этого вы должны использовать стандартные функции ntohl() и kin. Они работают с переменными явного размера (т. Е. uint16_t и uin32_t), а не с конкретным компилятором long, который необходим для переносимости.

Некоторые платформы предоставляют 64-битные версии в <endian.h>

2 голосов
/ 29 января 2010

В вашем примере данные 0x12345678.

Следовательно, ваше первое назначение байту:

byte = 0x12000000;

, который не помещается в байт, поэтому он обрезается до нуля.

попробовать:

byte = (data & bitmask) >> (sizeof(long) - 1) * 8);
2 голосов
/ 29 января 2010

Вы все неправильно переключаете.

#include <iostream>

int main (int argc, char * const argv[]) {
   long data = 0x12345678;
   int shift = (sizeof(long) - 1) * 8
   const unsigned long mask = 0xff;
   char byte = 0;

   for (long i = 0; i < sizeof(long); i++, shift -= 8) {
      byte = (data & (mask << shift)) >> shift;
   }
   return 0;
}

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

#include <tr1/cstdint> // To get uint16_t, uint32_t and so on.

inline uint16_t to_bigendian(uint16_t val, char bytes[2])
{
    bytes[0] = (val >> 8) & 0xffu;
    bytes[1] = val & 0xffu;
}

inline uint32_t to_bigendian(uint32_t val, char bytes[4])
{
   bytes[0] = (val >> 24) & 0xffu;
   bytes[1] = (val >> 16) & 0xffu;
   bytes[2] = (val >> 8) & 0xffu;
   bytes[3] = val & 0xffu;
}

Этот код проще и понятнее, чем ваш цикл. Это также быстрее. И, наконец, он распознается некоторыми компиляторами и автоматически превращается в операцию однобайтовой замены, которая потребуется для большинства процессоров.

0 голосов
/ 29 января 2010

потому что вы маскируете верхний байт из целого числа и затем не сдвигаете его обратно на 24 бита ...

Измените ваш цикл на:

for(long i = 0; i < sizeof(long); i++) {
        byte = (data & bitmask) >> 24;
        data <<= 8;
    }
...