【问题标题】:Combine two byte arrays of variable length through bit shifting通过位移组合两个可变长度的字节数组
【发布时间】:2018-07-12 11:53:42
【问题描述】:

我有两个字节数组,它们的长度可变,但总加起来最多 8 个字节。这些需要组合成一个长的。我可以通过创建一个字节数组并复制所需的数据来做到这一点。但我在想这也应该可以通过位移来实现。我一直在尝试这个(只用一个长度来简化):

        var bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7 };
        var bytes2 = new byte[] { 8 };
        unsafe
        {
            fixed (byte* b1 = bytes1)
            {
                fixed (byte* b2 = bytes2)
                {
                    ulong* bl1 = (ulong*)b1;
                    ulong v = (*bl1<< 8)  | (*b2);

                    var bytes = bytes1.Concat(bytes2).ToArray();

                    // These two are different:
                    Console.WriteLine(v); 
                    Console.WriteLine(BitConverter.ToUInt64(bytes, 0));
                }
            }
        }

我知道Concat 有效,但我也希望它也有效。

【问题讨论】:

  • 为什么不看看ToUInt64 是怎么做到的呢?它也使用位移位,但 unrolls 循环,因为此方法 性能关键
  • 另一方面,.NET Core 中的相同方法显然作弊并使用 Span 技巧将 8 个字节读取为 long
  • @PanagiotisKanavos 注意,他的数组不满足最小长度要求(小于 8 字节)。
  • 手动制作long时,勾选ending BitConverter.IsLittleEndian(你可能要Reverse()数组)

标签: c# arrays bit-shift


【解决方案1】:

首先,(ulong*)b1 是越界读取,因为数组的长度为 7 和 sizeof(ulong) == 8。下一次读取也以这种方式中断。对齐也是一个问题。我看不出有办法挽救这种做法。如果您真的在寻找性能,您可以读取 4 个字节,然后是 2 个字节,然后是 1 个字节。

我会遍历数组并移入每个字节:

ulong result = 0;

void MergeArray(byte[] bytes) {
 foreach (var b in bytes) {
  result = result << 8 | (ulong)b;
 }
}

MergeArray(bytes1);
MergeArray(bytes2);

使用本地函数进行代码共享。

如果数组长度支持该大小的读取,您可以通过将 4 个字节作为第一个块来提高性能。然后,取 2,再取 1。这样甚至没有循环,操作次数也最小化。

这是否好取决于您对性能的需求,而这必须与代码的易读性进行权衡。

【讨论】:

  • 值得检查BitConverter in the Full Framework does it。指针算术和移位。 .NET Core 中的相同方法,但 cheats 使用 Span 使用的相同内部方法。
  • @usr 是的,我也一直在考虑这个问题。不过我喜欢这个解决方案,我会试试看!
  • @TheCookiesDog 实际上,你的目标是什么?表现还是只是学习?
  • 两者都有一点,但主要是我想学习如何让它工作:)
猜你喜欢
  • 1970-01-01
  • 2014-08-08
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
  • 2021-11-30
  • 2017-03-17
  • 2020-11-20
相关资源
最近更新 更多