バイト内のビットを反転すると、なぜ次の出力が得られますか?
-
06-07-2019 - |
質問
仮定:
変換 リトルエンディアンからビッグまでのbyte [] エンディアンとは、ビットの順序を逆にすることを意味します byte []の各バイト。
これが正しいと仮定して、私はこれを理解するために以下を試しました:
byte[] data = new byte[] { 1, 2, 3, 4, 5, 15, 24 };
byte[] inverted = ToBig(data);
var little = new BitArray(data);
var big = new BitArray(inverted);
int i = 1;
foreach (bool b in little)
{
Console.Write(b ? "1" : "0");
if (i == 8)
{
i = 0;
Console.Write(" ");
}
i++;
}
Console.WriteLine();
i = 1;
foreach (bool b in big)
{
Console.Write(b ? "1" : "0");
if (i == 8)
{
i = 0;
Console.Write(" ");
}
i++;
}
Console.WriteLine();
Console.WriteLine(BitConverter.ToString(data));
Console.WriteLine(BitConverter.ToString(ToBig(data)));
foreach (byte b in data)
{
Console.Write("{0} ", b);
}
Console.WriteLine();
foreach (byte b in inverted)
{
Console.Write("{0} ", b);
}
convertメソッド:
private static byte[] ToBig(byte[] data)
{
byte[] inverted = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
var bits = new BitArray(new byte[] { data[i] });
var invertedBits = new BitArray(bits.Count);
int x = 0;
for (int p = bits.Count - 1; p >= 0; p--)
{
invertedBits[x] = bits[p];
x++;
}
invertedBits.CopyTo(inverted, i);
}
return inverted;
}
この小さなアプリケーションの出力は、私が期待したものとは異なります。
00000001 00000010 00000011 00000100 00000101 00001111 00011000
00000001 00000010 00000011 00000100 00000101 00001111 00011000
80-40-C0-20-A0-F0-18
01-02-03-04-05-0F-18
1 2 3 4 5 15 24
1 2 3 4 5 15 24
何らかの理由で、BitConverterを使用して印刷しない限り、データは同じままです。
何がわからないのですか?
更新
新しいコードは次の出力を生成します。
10000000 01000000 11000000 00100000 10100000 11110000 00011000
00000001 00000010 00000011 00000100 00000101 00001111 00011000
01-02-03-04-05-0F-18
80-40-C0-20-A0-F0-18
1 2 3 4 5 15 24
128 64 192 32 160 240 24
しかし、今言われたように、バイトを反転する必要があるため、とにかく私の方法は間違っています ビットではなく?
私が一緒に仕事をしているこのハードウェア開発者は、データを読み取れないのでビットを反転するように言われました。
これを使用しているコンテキスト
これを使用するアプリケーションは、実際には数字では機能しません。
ビットストリームをファイルに保存することになっています
1 =白、0 =黒。
ビットマップ256x64のピクセルを表します。
バイト0からバイト31は、ピクセルの最初の行を表します バイト32からバイト63の2行目のピクセル。
これらのビットを出力するコードがあります...しかし、開発者は言っています 私は間違った順番に並んでいます...彼はバイトは問題ないがビットはそうではないと言っています。
だから私は混乱してしまいました:p
解決
この時点であなたの方法は正しいかもしれません。エンディアンにはさまざまな意味があり、ハードウェアによって異なります。
通常、コンピューティングプラットフォーム間の変換に使用されます。ほとんどのCPUベンダー(現在)は、チップセットごとに同じビット順序を使用していますが、バイト順序は異なります。つまり、あるシステムから別のシステムに2バイトのintを渡す場合、ビットはそのままにして、バイト1と2を入れ替えます。つまり、
int somenumber -> byte[2]: somenumber[high],somenumber[low] ->
byte[2]: somenumber[low],somenumber[high] -> int newNumber
ただし、これは常に正しいとは限りません。一部のハードウェアはまだ反転BIT順序を使用しているため、お持ちの情報が正しい場合があります。ハードウェア開発者を信頼する必要があります。またはさらに詳しく調べます。
ウィキペディアでこれを読むことをお勧めします-常に素晴らしい情報源です:
http://en.wikipedia.org/wiki/Endianness
ToBigメソッドにはバグがあります。
最後に:
invertedBits.CopyTo(data, i);
}
return data;
これを次のように変更する必要があります:
byte[] newData = new byte[data.Length];
invertedBits.CopyTo(newData, i);
}
return newData;
入力データをリセットしているので、両方の配列が逆になります。問題は、配列が参照型であるため、元のデータを変更できることです。
他のヒント
いいえ。エンディアンとは、ビットではなく、バイトの順序を指します。ビッグエンディアンシステムは最上位バイトを最初に格納し、リトルエンディアンシステムは最下位バイトを最初に格納します。バイト内のビットは同じ順序のままです。
ToBig()関数は、ビットスワップされたデータではなく元のデータを返しているようです。
すでにグレイフェードが言っているように、エンディアンはビット順序に関するものではありません。
コードが期待どおりに動作しないのは、ToBigメソッドが送信する配列を変更するためです。つまり、メソッドを呼び出した後、配列は反転され、 data
と inverted
は同じ配列を指す2つの参照にすぎません。
メソッドの修正バージョンです。
private static byte[] ToBig(byte[] data) {
byte[] result = new byte[data.length];
for (int i = 0; i < data.Length; i++) {
var bits = new BitArray(new byte[] { data[i] });
var invertedBits = new BitArray(bits.Count);
int x = 0;
for (int p = bits.Count - 1; p >= 0; p--) {
invertedBits[x] = bits[p];
x++;
}
invertedBits.CopyTo(result, i);
}
return result;
}
編集:
バイト配列のエンディアンを変更するメソッドは次のとおりです。
static byte[] ConvertEndianness(byte[] data, int wordSize) {
if (data.Length % wordSize != 0) throw new ArgumentException("The data length does not divide into an even number of words.");
byte[] result = new byte[data.Length];
int offset = wordSize - 1;
for (int i = 0; i < data.Length; i++) {
result[i + offset] = data[i];
offset -= 2;
if (offset < -wordSize) {
offset += wordSize * 2;
}
}
return result;
}
例:
byte[] data = { 1,2,3,4,5,6 };
byte[] inverted = ConvertEndianness(data, 2);
Console.WriteLine(BitConverter.ToString(inverted));
出力:
02-01-04-03-06-05
2番目のパラメーターはワードサイズです。エンディアンネスはワード内のバイトの順序であるため、ワードの大きさを指定する必要があります。
編集2:
ビットを反転するためのより効率的な方法は次のとおりです。
static byte[] ReverseBits(byte[] data) {
byte[] result = new byte[data.Length];
for (int i = 0; i < data.Length; i++) {
int b = data[i];
int r = 0;
for (int j = 0; j < 8; j++) {
r <<= 1;
r |= b & 1;
b >>= 1;
}
result[i] = (byte)r;
}
return result;
}
1つの大きな問題は、ToBigが渡される data []
配列の内容を変更することです。
data
という名前の配列でToBigを呼び出して、結果を inverted
に割り当てていますが、ToBig内に新しい配列を作成していないため、両方の配列を使用する場合は、実際には配列 data
と inverted
を異なるものとして扱います。