各种类型的按位字节序交换
本文关键字:字节 交换 种类 类型 | 更新日期: 2023-09-27 18:36:37
在各种来源的帮助下,我在我的二进制读取器类中编写了一些SwapBytes
方法,这些方法在ushort
、uint
和ulong
中交换字节序,所有这些都使用原始C#中的按位运算,不需要任何unsafe
代码。
public ushort SwapBytes(ushort x)
{
return (ushort)((ushort)((x & 0xff) << 8) | ((x >> 8) & 0xff));
}
public uint SwapBytes(uint x)
{
return ((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24);
}
public ulong SwapBytes(ulong value)
{
ulong uvalue = value;
ulong swapped =
((0x00000000000000FF) & (uvalue >> 56)
| (0x000000000000FF00) & (uvalue >> 40)
| (0x0000000000FF0000) & (uvalue >> 24)
| (0x00000000FF000000) & (uvalue >> 8)
| (0x000000FF00000000) & (uvalue << 8)
| (0x0000FF0000000000) & (uvalue << 24)
| (0x00FF000000000000) & (uvalue << 40)
| (0xFF00000000000000) & (uvalue << 56));
return swapped;
}
我将如何创建相同的方法,但对于每种类型的签名版本,例如 short、int 和 long,仅使用与上述相同的方法,以及可以对上述方法进行哪些改进?
而不是在
概念上解构以分隔字节,然后反过来重新组装它们,您可以在概念上交换字节组,如下所示: (未测试)
public uint SwapBytes(uint x)
{
// swap adjacent 16-bit blocks
x = (x >> 16) | (x << 16);
// swap adjacent 8-bit blocks
return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
}
对 32 位没有多大帮助(或根本没有帮助),但对于 64 位它有帮助(未测试)
public ulong SwapBytes(ulong x)
{
// swap adjacent 32-bit blocks
x = (x >> 32) | (x << 32);
// swap adjacent 16-bit blocks
x = ((x & 0xFFFF0000FFFF0000) >> 16) | ((x & 0x0000FFFF0000FFFF) << 16);
// swap adjacent 8-bit blocks
return ((x & 0xFF00FF00FF00FF00) >> 8) | ((x & 0x00FF00FF00FF00FF) << 8);
}
对于有符号的类型,只需强制转换为无符号,执行此操作,然后强制转换回。
您应该查看以下 msdn 页面: http://msdn.microsoft.com/en-us/library/system.bitconverter.aspx
您可以简单地使用 Array.Reverse 和 bitConverter:
int value = 12345678;
byte[] bytes = BitConverter.GetBytes(value);
Array.Reverse(bytes);
int result = BitConverter.ToInt32(bytes, 0);
为了完整起见 - 现在有BinaryPrimitives.ReverseEndianness
.
只需在
开头将转换添加到 unsigned 并在末尾添加回已签名。
public long SwapBytes(long value)
{
return (long)SwapBytes((ulong)value);
}
可能需要手动内联对SwapBytes
的调用以获得最大性能。
另一方面,您可能希望避免交换,而倾向于直接从所需字节序的原始字节数组中读取数据。有关详细信息,请参阅在 C# 中读取大字节序数据的有效方法。
这可能是替换整数中位的最简单和懒惰的方法:
using System;
namespace BitSwap
{
class Program
{
static void Main()
{
//swaps bits {p, p+1, …, p+k-1} with bits {q, q+1, …, q+k-1} of n.
Console.WriteLine("n=");
uint n = uint.Parse(Console.ReadLine());
Console.WriteLine("p=");
int p = int.Parse(Console.ReadLine());
Console.WriteLine("q=");
int q = int.Parse(Console.ReadLine());
Console.WriteLine("k=");
int k = int.Parse(Console.ReadLine());
int i;
int s;
if ((p + k - 1) < 32 && (q + k - 1) < 32 && p > 0 && q > 0)
// for integer
{
for (i = p, s = q; i <= p + k - 1 && s <= q + k - 1; i++, s++)
{
uint firstBits = (n >> i) & 1;
uint secondBits = (n >> s) & 1;
uint maskFirstBits = (uint)1 << i;
uint maskSecondBits = (uint)1 << s;
n = (n & ~maskFirstBits) | (secondBits << i);
n = (n & ~maskSecondBits) | (firstBits << s);
}
Console.WriteLine("Result: {0}", n);
}
else
{
Console.WriteLine("Invalid entry.");
}
}
}
}