【问题标题】:How to convert Int32 array represented by byte array into Int32 array in C#如何将字节数组表示的Int32数组转换为C#中的Int32数组
【发布时间】:2017-05-04 18:41:21
【问题描述】:

我有一个由字节数组表示的 Int32 数组(每 4 个字节为 1 个 Int32),我想将它们转换为 Int32 数组(长度为 Byte.length/4)。 这是我想要的示例:

//byte[] buffer;
for (int i=0; i<buffer.Length; i+=4)
{
    Int32 temp0 = BitConverter.ToInt32(buffer, i);
    temp0 += 10;
    byte[] temp1 = BitConverter.GetBytes(temp0);
    for (int j=0;j<4;j++)
    {
        buffer[i + j] = temp1[j];
    }
}

但我不想复制它们,我只想能够告诉编译器它是 Int32 数组而不是字节数组(以便以后操作)。

我查看了这个How to Convert a byte array into an int array,但它将每个字节转换为 Int32,我想将每个 4 个字节转换为 Int32。 我也想这样做而不将其复制到另一个数组中以提高性能。

(我们可以假设硬件是本地字节序,用于小端表示的小端系统)。

【问题讨论】:

  • 听起来像是不安全和指针的工作
  • HereBitConverter.ToInt32(byte[], Int32)的源代码;我认为这段代码:fixed( byte * pbyte = &amp;value[startIndex]) {if( startIndex % 4 == 0) { // data is aligned return *((int *) pbyte); } 意味着它只是在对齐时将 4 个字节转换为 int32,它确实 转换,因此应该很快。有人可以验证吗?
  • @pm100 你能写出不安全的代码吗?我试过了,但我遇到了各种各样的错误:(

标签: c# .net arrays converter


【解决方案1】:

没有直接的方法来转换它们而不复制它们。您可以编写一个 linq 查询以将字节作为整数返回,但这不会让您操纵它们。

实现您想要的一种方法是将其包装在自己的类中:

public class IntArrayOverBytes
{
    private readonly byte[] bytes;
    public IntArrayOverBytes(byte[] bytes)
    {
        this.bytes = bytes;
    }

    public int this[int index]
    {
        get { return BitConverter.ToInt32(bytes, index * 4); }
        set { Array.Copy(BitConverter.GetBytes(value), 0, bytes, index * 4, 4); }
    }
}

通过这个类,您可以从byte 数组中读取int 值并将它们写回:

IntArrayOverBytes intArray = new IntArrayOverBytes(bytes);
intArray[5] = 2016;
Console.WriteLine(intArray[5]);

对于完整的Array 类功能,您需要添加更多代码。例如实现IEnumerable&lt;int&gt; 可能很有用:

public int Length => bytes.Length/4;
public IEnumerator<int> GetEnumerator()
{
    for(int i=0; i<Length; i++) yield return this[i];
}

【讨论】:

  • 你的代码肯定比我的更好,更易读,但我仍然认为有一种方法可以在没有复制的情况下进行转换,毕竟所有内存都已经设置为 Int32,我们只需要编译器知道它。我真的很关心这个应用程序的性能。
  • @pio 所以我猜你需要 cmets 中提到的unsafe 方法之一,但我没有这方面的经验。
  • @pio 但请注意,我的代码不复制数组,只复制对数组的引用。当然,它会“复制”您访问的值。
  • 你说得对,但我需要快速转换,继续使用这个包装类似乎会损害性能。
【解决方案2】:

这是不安全的版本之一(需要在项目构建属性中检查Allow unsafe code):

byte[] buffer = { 255,255,255,255, 255,255,255,127 }; // little endian { -1, int.MaxValue }

unsafe
{
    fixed (byte* bytePtr = buffer) // or = &buffer[0] 
    {
        for (int* intPtr = (int*)bytePtr; intPtr < bytePtr + buffer.Length; intPtr++)
        {
            *intPtr += 10; //intPtr is the address, and *intPtr is the value at that address
        }
    }
}

Debug.Print(string.Join(", ", buffer)); //"9, 0, 0, 0, 9, 0, 0, 128" { 9, int.MinValue + 9 }

fixed 用于获取数组的地址,并防止垃圾收集器将数组重定位到不同的内存位置。 bytePtr + buffer.Lengthbuffer 数组中最后一个元素之后的内存地址。在intPtr 地址上加 1 会将其移动 4 个字节。

我的猜测是,不安全的版本会比安全的BitConverter 版本快不到 2 倍,所以我认为风险不值得。我认为您可以从my previous answer 中的建议中获得更好的性能。

【讨论】:

  • 感谢您的帮助!但是我需要将数组传递给进一步处理(例如传递给函数),如果我只传递 int* 我不能将其视为 int[] (转换出错)。我开始放弃 C#,Ints 数组已经在内存中作为 int32 的正确位置,唯一需要做的就是告诉编译器将它们视为 Int 数组而不是字节数组..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多