Что делает этот кусок кода Tiled C ++?

Я пытаюсь выяснить цель этого куска кода, из Документация формата карты утилиты Tiled.

const int gid = data[i] |
data[i + 1] << 8 |
data[i + 2] << 16 |
data[i + 3] << 24;

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

3

Решение

Как вы заметили, << оператор сдвигает биты влево на заданное число.

Этот блок занимает 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

но я хотел бы привести полный пример.

1

Другие решения

Tiled хранит данные своего «Global Tile ID» (GID) слоя в массиве 32-разрядных целых чисел, закодированных в base64 и (необязательно) сжатых в файле XML.

Согласно документации, эти 32-разрядные целые числа хранятся в формате с прямым порядком байтов, то есть первый байт целого числа содержит наименее значащий байт числа. В качестве аналогии, в десятичном виде запись числа «1234» с прямым порядком байтов будет выглядеть 43214 является наименее значимой цифрой в числе (представляющим значение всего 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() собрать целое число в собственном формате, вместо того, чтобы писать и понимать код манипулирования байтами вручную).

5

По вопросам рекламы [email protected]