6

Lets say In C++ I got code like this..

void * target
uint32 * decPacket = (uint32 *)target;

So in C# it would be like..

byte[] target;
UInt32[] decPacket = (UInt32[])target;

Cannot convert type byte[] to uint[]

How do I convert this memory aligning thing C++ does to arrays to C#?

svick
  • 236,525
  • 50
  • 385
  • 514
SSpoke
  • 5,656
  • 10
  • 72
  • 124
  • I'll add that there is a dirty trick: http://stackoverflow.com/questions/619041/what-is-the-fastest-way-to-convert-a-float-to-a-byte/619307#619307 – xanatos Sep 02 '11 at 20:35
  • There's a better (and dirtier) trick which avoids iterations. See my answer below: http://stackoverflow.com/a/9666331/61061 – Omer Mor Mar 18 '12 at 11:19

7 Answers7

14

Well, something close would be to use Buffer.BlockCopy:

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

Note that the final argument to BlockCopy is always the number of bytes to copy, regardless of the types you're copying.

You can't just treat a byte array as a uint array in C# (at least not in safe code; I don't know about in unsafe code) - but Buffer.BlockCopy will splat the contents of the byte array into the uint array... leaving the results to be determined based on the endianness of the system. Personally I'm not a fan of this approach - it leaves the code rather prone to errors when you move to a system with a different memory layout. I prefer to be explicit in my protocol. Hopefully it'll help you in this case though.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • helped in my case yup. Seems in C++ it never copy's anything though.. it just realigns from byte scan to two bytes at once. Atleast this solution avoids me using loops to do this process. – SSpoke Sep 02 '11 at 20:36
  • 1
    In unsafe code, you can sort of do it - you can fix the array and use pointer math to iterate through the byte array as uint pointers directly. It works well, but it's basically reverting to a C/C++/native approach... – Reed Copsey Sep 02 '11 at 20:44
2

You can have the cake (avoid allocations) and eat it too (avoid iterations), if you're willing to move to the dark side.

Check out my answer to a related question, in which I demonstrate how to convert float[] to byte[] and vice versa: What is the fastest way to convert a float[] to a byte[]?

Community
  • 1
  • 1
Omer Mor
  • 5,216
  • 2
  • 34
  • 39
1

As Jon mentioned, Buffer.BlockCopy will work well for copying this.

However, if this is an interop scenario, and you want to access the byte array directly as uint[], the closest you can do is to the C++ approach would be to use unsafe code:

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++
}

I personally prefer making the copy, but if you need to avoid actually copying the data, this does allow you to work (in an unsafe context).

Community
  • 1
  • 1
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • wow awesome!.. I'll have to try this out! what is? `CallInteropMethod` – SSpoke Sep 02 '11 at 20:40
  • @SSpoke: C#, in an unsafe context, can act very much like C++ - and get all that pointer goodness/nastiness back ;) – Reed Copsey Sep 02 '11 at 20:41
  • The `CallInteropMethod` was just saying "this is something to fill in the byte[]" - normally, this wouldn't be used in pure managed code... – Reed Copsey Sep 02 '11 at 20:41
  • Blah I thought about it.. and I was sick of C++.. that's why I am porting this to .NET.. so I'll keep it strictly C#.. without any unsafe code. (Honestly I am very confused :P I have to wrap all the brackets around all my logic? then I also have encPacket which also is bytes -> uint32 blah too complicated hehe – SSpoke Sep 02 '11 at 20:45
  • @SSpoke: Good call (unless this is perf. critical code) - I'd typically avoid this in all situations except those where I've profiled and discovered it's very, very difficult to handle otherwise without major implications. – Reed Copsey Sep 02 '11 at 20:47
0

I used BitConverter.ToUInt32() - https://learn.microsoft.com/en-us/dotnet/api/system.bitconverter.touint32?view=netcore-3.1

byte[] source = new byte[n];
UInt32 destination;

destination = BitConverter.ToUInt32(source, 0);

It seems to work fine for me.

Alex Seceleanu
  • 505
  • 4
  • 10
0

Years late but maybe this will help someone else. (It's also kind of new.)

We can do a c++ style reinterpret cast (sort of) using the new Span<> in .Net Core 2.1 or later. There are no heap memory allocations so it is very fast.

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;

If byte[] is needed, as stated in the question, then the above can be taken one step further. (This would allocate memory and copy but it is still fast.)

byte[] byteArray = MemoryMarshal.AsBytes<uint>(uIntArray).ToArray();
SunsetQuest
  • 8,041
  • 2
  • 47
  • 42
0

You can use Buffer.BlockCopy. Rather than Array.Copy, BlockCopy does a byte-level copy without checking the array types are fully compatible.

Like so:

uint[] array = new uint[bytes.Length/4];
Buffer.BlockCopy(bytes, 0, array, 0, bytes.Length);
thecoop
  • 45,220
  • 19
  • 132
  • 189
  • I am pretty sure if you do this, you will get an exception. "Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection" – Cubicle.Jockey Sep 02 '11 at 20:59
  • Why? The length to the argument to `BlockCopy` is specified in bytes. – thecoop Sep 04 '11 at 15:42
-1

Loop over all array items and call Convert.ToUint32() on each of them.Here:

 Uint32[] res = new Uint32[target.Length];
 for(int i = 0;i <= target.Length;i++) 
 {
     res[i] = Convert.ToUint32(target[i]);
 }

Here is an official link from MSDN. http://msdn.microsoft.com/en-us/library/469cwstk.aspx

  • will this even work? it will create as much `UInt32`'s are there is byte's.. I have to make 2 bytes into 1 `uint` though. – SSpoke Sep 02 '11 at 20:37
  • I think `new Uint32[target.length]` has to be `new Uint32[target.length / sizeof(UInt32)]` – SSpoke Sep 02 '11 at 20:39
  • This requires using BitConverter if you want to loop. This will give you a unit with the value of the individual byte - which is very different... – Reed Copsey Sep 02 '11 at 20:40
  • Feel free to edit if you are sure that that is correct @SSpoke.I am always open for people willing to fix my mistakes. –  Sep 02 '11 at 20:41