将int[]转换为byte:如何将int[]视为byte[]?

3

解释一下:我有一个整数数组作为输入。我需要将它转换成字节数组,其中1个整数=4个字节(大端)。在C++中,我可以轻松地进行强制类型转换,然后像访问字节数组一样访问字段,而不用复制或计算数据——直接访问即可。在C#中是否也可以实现这种操作?并且在C# 2.0中是否也可以实现?


1
你的应用程序将在本地大端平台上运行吗?如果不是,那么你至少需要复制字节以进行转换。 - M.Babcock
5个回答

5

是的,可以使用不安全的代码:

int[] arr =...
fixed(int* ptr = arr) {
    byte* ptr2 = (byte*)ptr;
    // now access ptr2[n]
}

如果编译器报错,请加上(void*)
    byte* ptr2 = (byte*)(void*)ptr;

刚刚测试了一下,编译器没有报错。(至少在使用C#4的情况下) - CodesInChaos

4
你可以创建一个4倍于int[]长度的byte[]。 然后,你遍历整数数组并从中获取字节数组:
BitConverter.GetBytes(int32);

接下来,您需要使用Buffer.BlockCopy将此函数的4个字节复制到正确的偏移量(i * 4)处,保留HTML标签。

BitConverter Buffer.BlockCopy


2

没有办法在不复制数据的情况下访问它。实际上,在这个语境中,“访问”和“复制”本质上是同义词。即使只是将 i 作为右值,也是访问变量的最小可能方式,会复制它的值。 - David Schwartz
@David 不,ref i不会复制该值 :p - Marc Gravell
@MarcGravell,那么它确切地对该值做了什么?在寄存器以外的位置上,您可以对值执行的唯一操作是复制它。(在您访问它之前,该值在多少个位置上?在您访问它时,它在多少个位置上?如果第二个数字大于第一个数字,则为副本。) - David Schwartz
@David 另一种选择是获取地址(因此使用 ref)- 这实际上是一个严肃的问题,因为在 struct 的情况下,您可以使用 ref 将地址传递给方法,然后在方法内部访问成员和调用方法,而不必复制该值。这种方法在 XNA 中很常见,因为 struct 是常见的避免 GC 的方式。 - Marc Gravell
哦,请。尽管从技术上讲David是正确的(int毕竟没有任何成员),但显然OP谈到了拥有一个完整副本的数组,而不是在CPU寄存器等地方临时复制单个值。 - CodesInChaos
显示剩余3条评论

1

如果你编写不安全的代码,你可以修复内存中的数组,获取指向其开头的指针,并将该指针强制转换。

unsafe
{
  fixed(int* pi=arr)
  {
    byte* pb=(byte*)pi;
    ...
  }
}

在 .net 中,数组以元素数为前缀,因此您不能安全地在指向相同数据的 int[]byte[] 之间进行转换。您可以在 uint[]int[] 之间进行强制类型转换(至少就 .net 而言,C#本身对此特性的支持有些不一致)。
还有一种基于联合的技巧可以重新解释转换引用,但我强烈建议不要使用它。
从本机字节顺序中获取单个整数的常规方法是使用BitConverter,但它相对较慢。手动编写的代码通常更快。当然,它也不支持反向转换。
一种手动转换的方式,假设采用小端模式(在我的2.6GHz i3上每秒约可读取4亿次):
byte GetByte(int[] arr, int index)
{
  uint elem=(uint)arr[index>>2];
  return (byte)(elem>>( (index&3)* 8));
}

如果你想使用托管代码,我建议手动编写使用位移操作来访问单个字节的代码;如果你想追求最后一点性能,则需要使用指针。

此外,你还需要注意字节序问题。其中一些方法仅支持本机字节序。


位移操作非常重要。特别是,有些平台甚至不允许使用不安全的操作。 - Marc Gravell

1
在类型安全的托管代码中最简单的方法是使用:
byte[] result = new byte[intArray.Length * sizeof(int)];
Buffer.BlockCopy(intArray, 0, result, 0, result.Length);

这并不完全符合我认为你的问题所问的,因为在小端架构(如x86或ARM)上,结果数组最终将成为小端,但我相信C++也是如此。

如果您可以使用unsafe{},则有其他选项:

unsafe{
  fixed(byte* result = (byte*)(void*)intArray){
    // Do stuff with result.
  }
}

2
我认为BlockCopy使用本地字节顺序,而不是小端字节顺序。当然,CLR通常运行在小端架构上,因此实际上很少有区别。 - CodesInChaos
@CodeInChaos,是的 - 完全正确。我的措辞有点不够严谨。我真正想表达的是,他可能选择的平台导致了小端序,而 OP 需要大端序的结果。我已经修改了措辞,使事情稍微清晰一些。 - sblom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接