如何将字节数组转换为UInt32数组?

6
假设我在C++中得到的代码如下所示...
void * target
uint32 * decPacket = (uint32 *)target;

所以在C#中,它会像这样...
byte[] target;
UInt32[] decPacket = (UInt32[])target;

无法将 byte[] 类型转换为 uint[] 类型

如何将 C++ 中的内存对齐方式转换为 C# 中的数组?


我要补充一点,有一个不太光彩的技巧:https://dev59.com/fXRB5IYBdhLWcg3wc280#619307 - xanatos
有一个更好(也更“肮脏”)的技巧可以避免迭代。请参见下面的答案:https://dev59.com/glrUa4cB1Zd3GeqPoegX#9666331 - Omer Mor
7个回答

14

使用Buffer.BlockCopy可能会更接近预期:

uint[] decoded = new uint[target.Length / 4];
Buffer.BlockCopy(target, 0, decoded, 0, target.Length);

请注意,BlockCopy 的最后一个参数始终是要复制的字节数,而不管您要复制的类型。

在C#中,您不能将 byte 数组视为 uint 数组(至少在安全代码中不行;我不知道在不安全代码中是否可以),但是 Buffer.BlockCopy 将会将 byte 数组的内容填充到 uint 数组中... 后果取决于系统的字节顺序。个人而言,我不喜欢这种方法 - 当您转移到具有不同内存布局的系统时,这样的代码容易出错。我更喜欢在协议中明确指定。但愿这个提示对您有所帮助。


在我的情况下有所帮助。似乎在C++中它从不复制任何东西,只是从字节扫描重新对齐到两个字节。至少这个解决方案避免了我使用循环来执行此过程。 - SSpoke
1
在不安全的代码中,你可以做到 - 你可以修复数组并使用指针数学直接迭代字节数组作为uint指针。这很有效,但基本上是回归到C / C++ / native方法... - Reed Copsey

2
你可以在转向“黑暗面”的情况下既拥有蛋糕(避免分配),又能吃掉它(避免迭代)。
请参考我回答相关问题的答案,其中我演示了如何将float[]转换为byte[],反之亦然:如何将float[]转换为byte[]的最快方法是什么?

1

正如Jon所提到的那样, Buffer.BlockCopy可以很好地用于复制此内容。

然而,如果这是一个交互操作场景,并且您想要直接访问字节数组作为uint[],最接近C++方法的做法是使用不安全代码:

byte[] target;
CallInteropMethod(ref target);

fixed(byte* t = target)
{
   uint* decPacket = (uint*)t;

   // You can use decPacket here the same way you do in C++
}

我个人更喜欢复制数据,但如果你需要避免实际复制数据,这种方法可以让你在不安全的上下文中工作。


哇,太棒了!我得试试这个!什么是 CallInteropMethod - SSpoke
@SSpoke:在不安全的上下文中,C#可以非常像C++一样运行,并获得所有指针的好处/恶心感。 - Reed Copsey
CallInteropMethod 只是在说“这是要填充 byte[] 的内容” - 通常,在纯托管代码中不会使用它... - Reed Copsey
我考虑了一下... 我已经厌倦了C++...这就是为什么我要将它移植到.NET..所以我会严格使用C#..不使用任何不安全的代码。(老实说,我很困惑:P 我必须在所有逻辑周围包装所有括号吗?然后我还有一个encPacket,它也是字节->uint32,太复杂了哈哈) - SSpoke
@SSpoke:不错的建议(除非这是关键性能代码)- 在没有经过分析并发现其他处理方式会带来重大影响的情况下,我通常会避免使用它。 - Reed Copsey

0

您可以使用Buffer.BlockCopy。与Array.Copy不同,BlockCopy进行字节级别的复制,而不检查数组类型是否完全兼容。

像这样:

uint[] array = new uint[bytes.Length/4];
Buffer.BlockCopy(bytes, 0, array, 0, bytes.Length);

我非常确定,如果你这样做,你会得到一个异常。 “偏移量和长度超出了数组的边界,或者计数大于从索引到源集合末尾的元素数量。” - Cubicle.Jockey
为什么?BlockCopy 函数的参数长度是以字节为单位指定的。 - thecoop

0

虽然有些晚,但也许这会对其他人有所帮助。(这也是比较新的方法。)

我们可以使用新的Span<>.Net Core 2.1或更高版本中进行类似于c++风格的reinterpret cast。由于没有堆内存分配,因此速度非常快。

Span<byte> byteArray = MemoryMarshal.AsBytes<uint>(uIntArray);
// with span we can get a byte, set a byte, iterate, and more.
byte someByte = byteSpan[2]; 
byteSpan[2] = 33;

如果需要byte[],就像问题中所述,那么可以进一步采取上述方法。(这将分配内存并复制,但仍然很快。)
byte[] byteArray = MemoryMarshal.AsBytes<uint>(uIntArray).ToArray();

这将数组转换为相反的方式。最初的问题是关于从字节数组转换为无符号整数数组。 - undefined

0

-1
循环遍历所有数组项并对每个项调用Convert.ToUInt32()。在这里:
 Uint32[] res = new Uint32[target.Length];
 for(int i = 0;i <= target.Length;i++) 
 {
     res[i] = Convert.ToUint32(target[i]);
 }

这是来自MSDN的官方链接。 http://msdn.microsoft.com/en-us/library/469cwstk.aspx


这个会起作用吗?它将创建与字节数量相同的UInt32。但是我必须把2个字节变成1个uint - SSpoke
我认为 new Uint32[target.length] 应该改为 new Uint32[target.length / sizeof(UInt32)] - SSpoke
如果你想要循环,这就需要使用BitConverter。这将给你一个具有单个字节值的单位 - 这非常不同... - Reed Copsey
如果您确定是正确的话,可以随意编辑@SSpoke。我一直欢迎愿意纠正我的错误的人。 - user744186

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