【问题标题】:Bitwise endian swap for various types各种类型的位字节序交换
【发布时间】:2013-10-24 08:10:20
【问题描述】:

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

【问题讨论】:

  • 为什么首先需要交换?您不能使用输入字节数组中的所需字节顺序直接读取吗?根据我的经验,这会导致更快、更容易阅读和更容易测试代码。

标签: c# .net


【解决方案1】:

您可以在概念上交换字节组,而不是在概念上解构为单独的字节然后重新组装它们,如下所示:(未测试)

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

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

【讨论】:

  • 并且保留cmets。我知道在弄清楚这些位掩码和四处移动有什么好处之前我会很困惑!
【解决方案2】:

你应该看看下面的 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);

【讨论】:

  • 正如我所说,我想使用按位运算符,而不是在类型之间转换和交换数组
  • 这肯定会比 OP 给出的代码慢得多。您可以对其进行基准测试并查看。
  • BitConverter 使用本机字节序,速度很慢,Array.Reverse 垃圾邮件是不必要的实例,使其更慢。
  • 很好。我真的不想对其进行基准测试。我相信你。如果性能不是问题,这只是一种简短(且易于维护)的编写方式。
【解决方案3】:

只需在开始时添加一个unsigned并返回到最后签名。

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

可能需要手动填写SwapBytes以实现最大性能。


在不同的备注中,您可能希望避免交换,有利于直接从所需的endianness中从原始字节数组读取数据。详情请见Efficient way to read big endian data in C#

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      • 2014-09-19
      • 2022-11-23
      • 1970-01-01
      • 2015-03-26
      • 1970-01-01
      相关资源
      最近更新 更多