Я пытаюсь выяснить цель этого куска кода, из Документация формата карты утилиты Tiled.
const int gid = data[i] |
data[i + 1] << 8 |
data[i + 2] << 16 |
data[i + 3] << 24;
Похоже, что есть некоторое «упорядочение» и смещение битов, но я понятия не имею, какова цель этого в контексте использования данных из плиточной программы.
Как вы заметили, <<
оператор сдвигает биты влево на заданное число.
Этот блок занимает data[]
массив, который имеет четыре (предположительно один байт) элемента и «кодирует» эти четыре значения в одно целое число.
Пример времени!
data[0] = 0x3A; // 0x3A = 58 = 0011 1010 in binary
data[1] = 0x48; // 0x48 = 72 = 0100 1000 in binary
data[2] = 0xD2; // 0xD2 = 210 = 1101 0010 in binary
data[3] = 0x08; // 0x08 = 8 = 0000 1000 in binary
int tmp0 = data[0]; // 00 00 00 3A = 0000 0000 0000 0000 0000 0000 0011 1010
int tmp1 = data[1] << 8; // 00 00 48 00 = 0000 0000 0000 0000 0100 1000 0000 0000
int tmp2 = data[2] << 16; // 00 D2 00 00 = 0000 0000 1101 0010 0000 0000 0000 0000
int tmp3 = data[3] << 24; // 08 00 00 00 = 0000 1000 0000 0000 0000 0000 0000 0000
// "or-ing" these together will set each bit to 1 if any of the bits are 1
int gid = tmp1 | // 00 00 00 3A = 0000 0000 0000 0000 0000 0000 0011 1010
tmp2 | // 00 00 48 00 = 0000 0000 0000 0000 0100 1000 0000 0000
tmp3 | // 00 D2 00 00 = 0000 0000 1101 0010 0000 0000 0000 0000
tmp4; // 08 00 00 00 = 0000 1000 0000 0000 0000 0000 0000 0000
gid == 147998778;// 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
Теперь вы только что закодировали четыре однобайтовых значения в одно четырехбайтовое целое число.
Если вам (по праву) интересно, зачем кому-то хотеть пройти через все эти усилия, когда вы можете просто использовать byte
и сохраните четыре однобайтовых фрагмента данных непосредственно в четыре байта, тогда вы должны проверить этот вопрос:
int, короткая, байтовая производительность в последовательных циклах for
Бонус Пример!
Чтобы вернуть ваши закодированные значения, мы используем оператор «и» вместе со сдвигом вправо >>
:
int gid = 147998778; // 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
// "and-ing" will set each bit to 1 if BOTH bits are 1
int tmp0 = gid & // 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
0x000000FF; // 00 00 00 FF = 0000 0000 0000 0000 0000 0000 1111 1111
int data0 = tmp0; // 00 00 00 3A = 0000 0000 0000 0000 0000 0000 0011 1010
int tmp1 = gid & // 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
0x0000FF00; // 00 00 FF 00 = 0000 0000 0000 0000 1111 1111 0000 0000
tmp1; //value of tmp1 00 00 48 00 = 0000 0000 0000 0000 0100 1000 0000 0000
int data1 = tmp1 >> 8; // 00 00 00 48 = 0000 0000 0000 0000 0000 0000 0100 1000
int tmp2 = gid & // 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
0x00FF0000; // 00 FF 00 00 = 0000 0000 1111 1111 0000 0000 0000 0000
tmp2; //value of tmp2 00 D2 00 00 = 0000 0000 1101 0010 0000 0000 0000 0000
int data2 = tmp2 >> 16; // 00 00 00 D2 = 0000 0000 0000 0000 0000 0000 1101 0010
int tmp3 = gid & // 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
0xFF000000; // FF 00 00 00 = 1111 1111 0000 0000 0000 0000 0000 0000
tmp3; //value of tmp3 08 00 00 00 = 0000 1000 0000 0000 0000 0000 0000 0000
int data3 = tmp3 >> 24; // 00 00 00 08 = 0000 0000 0000 0000 0000 0000 0000 1000
Последнее «and-ing» для tmp3 не требуется, поскольку биты, которые «отваливаются» при сдвиге, просто теряются, а входящие биты равны нулю. Так:
gid; // 08 D2 48 3A = 0000 1000 1101 0010 0100 1000 0011 1010
int data3 = gid >> 24; // 00 00 00 08 = 0000 0000 0000 0000 0000 0000 0000 1000
но я хотел бы привести полный пример.
Tiled хранит данные своего «Global Tile ID» (GID) слоя в массиве 32-разрядных целых чисел, закодированных в base64 и (необязательно) сжатых в файле XML.
Согласно документации, эти 32-разрядные целые числа хранятся в формате с прямым порядком байтов, то есть первый байт целого числа содержит наименее значащий байт числа. В качестве аналогии, в десятичном виде запись числа «1234» с прямым порядком байтов будет выглядеть 4321
— 4
является наименее значимой цифрой в числе (представляющим значение всего 4), 3
является следующим наименее значимым (представляющим 30) и так далее. Единственное различие между этим примером и тем, что делает Tiled, состоит в том, что мы используем десятичные цифры, в то время как Tiled использует байты, которые фактически являются цифрами, каждая из которых может содержать 256 различных значений вместо 10.
Если мы думаем о коде в терминах десятичных чисел, то на самом деле довольно легко понять, что он делает. Он в основном восстанавливает целочисленное значение из цифр, выполняя только это:
int digit[4] = { 4, 3, 2, 1 }; // our decimal digits in little-endian order
int gid = digit[0] +
digit[1] * 10 +
digit[2] * 100 +
digit[3] * 1000;
Это просто перемещение каждой цифры в позицию, чтобы создать полное целочисленное значение. (В двоичном коде сдвиг битов на кратные 8 подобен умножению на десятичные степени; он перемещает значение в следующий слот «значащая цифра»)
Более подробную информацию о порядке байтов и порядке байтов можно найти в разделе О священных войнах и призыве к миру, важный (и занимательно написанный) документ 1980 года, в котором Дэнни Коэн утверждал о необходимости стандартизации порядка байтов для сетевых протоколов. (спойлер: big-endian в конечном итоге выиграл эту битву, и поэтому представление целых чисел с прямым порядком байтов теперь является стандартным способом представления целых чисел в файлах и сетевых передачах — и используется в течение десятилетий. Tiled использует целочисленные порядковые числа в своих Формат файла несколько необычен. И приводит к необходимости кода, подобного коду, который вы цитировали, чтобы надежно преобразовать целые числа с прямым порядком байтов в файле данных в собственный формат компьютера. Если бы они хранили свои данные в стандартном формате с прямым порядком байтов каждая операционная система предоставляет стандартные служебные функции для преобразования туда и обратно из старшего порядка в нативный, и вы могли бы просто вызвать ntohl()
собрать целое число в собственном формате, вместо того, чтобы писать и понимать код манипулирования байтами вручную).