各种类型的按位端交换

时间:2013-10-24 08:10:21

标签: c# .net

在各种来源的帮助下,我在我的二进制阅读器类中编写了一些SwapBytes方法,用于在ushortuintulong中交换endian,所有方法都使用所有在原始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,只使用与上面相同的方法,以及可以对上述方法进行哪些改进?

4 个答案:

答案 0 :(得分:14)

而不是从概念上解构为单独的字节,然后以相反的方式重新组合它们,你可以在概念上交换字节组,如下所示:(未经测试)

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);
}

对于签名类型,只需转换为无符号,执行此操作,然后转换回来。

答案 1 :(得分:7)

您应该查看以下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);

答案 2 :(得分:2)

只需在开头添加一个转换为unsigned,然后返回到最后签名。

public long SwapBytes(long value)
{
    return (long)SwapBytes((ulong)value);
}

可能需要手动内联调用SwapBytes以获得最佳性能。


另外,您可能希望避免交换,而是直接以所需的字节顺序从原始字节数组中读取数据。有关详细信息,请参阅Efficient way to read big endian data in C#

答案 3 :(得分:-1)

这可能是替换整数位的最简单和最懒惰的方法:

my $object = TiedThing->new({
    lines => [join("\n", 1..9, 1..9)],
    customvalue => "custom!",
});
say "can call custom method: " . $object->custom;
say "raw read with <>: " . <$object>;
my $buf;
read($object, $buf, 10);
say "raw read with read(): " . $buf;
undef $buf;
$object->read($buf, 10);
say "OO read via IO::File::read (end): " . $buf;
my $checksummer = Digest::MD5->new;;
$checksummer->addfile($object);
say "Md5 read: " . $checksummer->hexdigest;
my $dupto = IO::Handle->new;
# Doesn't break/return undef; still not usable without implementing
# more state sharing inside the object.
say "Can dup handle: " . $dupto->fdopen($object, "r");

my $archiver = Archive::Zip->new;
# Dies, but long after the fdopen() call. Can be fixed by implementing more
# PerlIO methods.
$archiver->readFromFileHandle($object);