понедельник, 18 марта 2013 г.

C++: Определение порядка байт для различных платформ

В зависимости от процессора данные в памяти могут хранится по-разному. Возьмём для примера целое число размером 4 байта со значением 0x44332211 в 16-ной системе счисления. Для систем с остроконечным порядком (младшие байты располагаются по младшим адресам) это число будет хранится в виде последовательности байт 0x11 0x22 0x33 0x44. Для систем с тупоконечным порядком то же число будет хранится как 0x44 0x33 0x22 0x11. Есть ещё смешанные способы хранения. Об этом хорошо написано в http://ru.wikipedia.org/wiki/Порядок_байтов. На практике возникает задача - определить порядок хранения.


Для C++ данная задача решается следующим образом:
enum ENDIAN
{
 ENDIAN_UNDEFINED = 0,
 ENDIAN_LITTLE, // Порядок от младшего к старшему, остроконечный (младшие байты по младшим адресам)
 ENDIAN_MIDDLE, // Смешанный порядок
 ENDIAN_BIG     // Порядок от старшего к младшему, тупоконечный, сетевой порядок (старшие байты по младшим адресам)
};

ENDIAN which_endian()
{
 if (sizeof(long) == 1)
  return ENDIAN_UNDEFINED;

 union
 {
  long l;
  unsigned char m[sizeof(long)];
 } x;

 // HERE: нельзя в x.l присвоить большее значение, например, x.l=0x8877665544332211; Это приведёт к ошибке компиляции на g++
 x.l = 0;
 for (size_t i=1; i<sizeof(long); i++)
  x.l += i << (8*i);

 bool is_ascending = true;
 bool is_descending = true;
 for (size_t i=1; i<sizeof(long); i++)
 {
  if (x.m[i-1] < x.m[i])
   is_descending = false;
  if (x.m[i-1] > x.m[i])
   is_ascending = false;
 }

 if (is_ascending)
  return ENDIAN_LITTLE;

 if (is_descending)
  return ENDIAN_BIG;

 return ENDIAN_MIDDLE;
}

Особенность данного решения в том, что она рассматривает любые размеры long, включая 1, 2, 4, 8 байт. А также в том, что определяет смешанный порядок.

Комментариев нет:

Отправить комментарий