Break it down. What are we doing? Work from the semantic level, not from the level of pointers.
- We have a byte array with some number of bytes.
- We take two bytes at a time and alias them as 16-bit unsigned integers
- We extract the 16-bit unsigned integer, convert it to a 32-bit unsigned integer, and assign that to an array element.
Now we have a specification. Write a method for each interesting operation. The only interesting operation is turning two bytes into one ushort; everything else is done for you by the compiler.
static ushort BytesToUshort(byte b1, byte b2)
{
// You can implement this method
}
Great. Now we have a tool we can use. What bytes do we want? The bytes at i*2 and i*2+1. So:
for (i = 0; i < 4; i++) {
hv[i] = BytesToUshort(h1[i*2], h1[i*2+1]);
}
And we're done.
Don't try to translate pointer manipulation code to C#; you can do it but it will not be good C# code. Write code that has the same effect but uses the conventions of C#.
A technique that might help is to rewrite the code so that it is less awful C code; this is terrible. If you rewrote the original code into C like this first:
uint16_t *ps = (uint16_t*)h1;
for (i = 0; i < 4; i++)
hv[i] = ps[i];
I daresay that it would have been a lot easier to understand conceptually what was going on here.
System.BitConverter.ToUInt16The BitConverter class will be helpful in conversion of any code containing a pointer cast.i[hv] = i[(uint16_t*)h1];