3

Tiled ユーティリティの map format documentationから、このコードの目的を理解しようとしています。

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

「or-ing」とビットのシフトがあるように見えますが、タイル化されたプログラムからのデータを使用するというコンテキストでは、これの目的が何であるかはわかりません。

4

2 に答える 2

5

Tiled は、レイヤーの「グローバル タイル ID」(GID) データを 32 ビット整数の配列に格納し、base64 でエンコードして (オプションで) XML ファイルに圧縮します。

ドキュメントによると、これらの 32 ビット整数はリトル エンディアン形式で格納されます。つまり、整数の最初のバイトには、数値の最下位バイトが含まれます。類推として、10 進数では、数値「1234」をリトル エンディアンで書くと次のようになり4321ます4330)など。この例と Tiled が行っていることとの唯一の違いは、10 進数を使用しているのに対し、Tiled はバイトを使用していることです。これは事実上、10 ではなく 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;

各桁を所定の位置に移動して、完全な整数値を作成するだけです。(2 進数では、8 の倍数でビットをシフトすることは、10 進数で 10 の累乗を掛けることに似ています。値を次の「有効桁数」スロットに移動します)

ビッグ エンディアンとリトル エンディアンの詳細と、その違いが重要な理由については、On Holy Wars And A Plea For Peaceを参照してください。は、1980 年の重要な (そして面白く書かれた) ドキュメントで、Danny Cohen が、ネットワーク プロトコルのシングル バイト順の標準化の必要性を主張しました。(ネタバレ: ビッグエンディアンは最終的にその戦いに勝ったため、整数のビッグエンディアン表現は現在、ファイルやネットワーク伝送で整数を表す標準的な方法であり、何十年もの間そうでした。ファイル形式はやや珍しい. データ ファイル内のリトルエンディアン整数をコンピュータのネイティブ形式に確実に変換するには、引用したコードのようなコードが必要になります. 標準のビッグエンディアン形式でデータを保存した場合、すべての OS は、ビッグ エンディアンからネイティブに変換するための標準ユーティリティ関数を提供します。ntohl()この種のバイト操作コードを手動で記述して理解する必要はありません)。

于 2014-04-25T01:07:05.040 に答える
1

ご指摘のとおり、<<演算子は指定された数値だけビットを左にシフトします。

このブロックは、data[]4 つの要素 (おそらく 1 バイト) を持つ配列を受け取り、それらの 4 つの値を 1 つの整数に "エンコード" します。

例の時間!

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

これで、4 つの 1 バイト値が 1 つの 4 バイト整数にエンコードされました。

byte(当然のことながら) 疑問に思っている場合は、1 バイトの 4 つのデータを直接使用して 4 バイトに格納できるのに、なぜそのような努力をする必要があるのでしょうか。次の質問を確認してください。

連続する 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 に答える