3

我试图从Tiled 实用程序的地图格式文档中找出这段代码的用途。

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

看起来有一些“or-ing”和位移,但我不知道在使用平铺程序中的数据的情况下这样做的目的是什么。

4

2 回答 2

5

Tiled 将其图层“全局 Tile ID”(GID) 数据存储在一个 32 位整数数组中,并在 XML 文件中进行 base64 编码和(可选)压缩。

根据文档,这些 32 位整数以 little-endian 格式存储——也就是说,整数的第一个字节包含数字的最低有效字节。作为一个类比,在十进制中,用小端写数字“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 的倍数就像乘以十进制的 10 的幂;它将一个值移动到下一个“有效数字”槽中)

有关大端和小端的更多信息,以及为什么差异很重要,请参阅On Holy Wars And A Plea For Peace,这是 1980 年的一份重要(而且写得很有趣)的文件,其中 Danny Cohen 主张需要标准化网络协议的单字节顺序。(剧透:big-endian 最终赢得了这场战斗,因此整数的 big-endian 表示现在是在文件和网络传输中表示整数的标准方式 - 并且已经存在了几十年。Tiled 在他们的文件中使用 little-endian 整数文件格式有点不寻常。导致需要像您引​​用的代码这样的代码,以便可靠地将数据文件中的小端整数转换为计算机的本机格式。如果他们以标准的大端格式存储数据,每个操作系统都提供标准的实用程序函数,用于从大端到本地来回转换,您可以简单地调用ntohl()组装本机格式的整数,而不是需要手动编写和理解这种字节操作代码)。

于 2014-04-25T01:07:05.040 回答
1

如您所述,<<运算符将位向左移动给定的数字。

该块采用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,那么您应该查看这个问题:

背靠背for循环中的int,short,byte性能


奖金示例!

为了取回您的编码值,我们使用“and”运算符和右移>>

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

不需要 tmp3 的最后一个“and-ing”,因为移位时“脱落”的位刚刚丢失并且进入的位为零。所以:

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

但我想提供一个完整的例子。

于 2014-04-25T05:27:45.270 回答