0

How would I port this piece of C Code to C#? It is a UPC Key Recovery Tool.

hv is a uint32_t array with 4 elements. h1 is a uint8_t array with 16 elements

uint32_t hv[4] = ...
uint8_t h1[16] = ...

for (i = 0; i < 4; i++) {
    hv[i] = *(uint16_t *)(h1 + i*2);
}

While this is valid C code I cannot seem to port this to C# without it giving me errors. Does anybody have an idea what I could do?

I've tried declaring hv as a uint array and h1 as a byte array.

16
  • You'll be wanting System.BitConverter.ToUInt16 The BitConverter class will be helpful in conversion of any code containing a pointer cast. Commented Dec 20, 2017 at 22:27
  • 2
    Don't think about it at the level of pointers. Say at a high level what the program fragment does. "I have an array of 4 uints and an array of 16 bytes; I wish to write four uints to the array such that..." Commented Dec 20, 2017 at 22:31
  • 2
    Now you've written a specification. Implement that specification in C# using the idioms of C#. Commented Dec 20, 2017 at 22:32
  • The full original c code can be found on haxx.in/upc_keys.c Commented Dec 20, 2017 at 22:34
  • @EricLippert: I wonder how many people would dare give this a try if the loop body were the equivalent i[hv] = i[(uint16_t*)h1]; Commented Dec 20, 2017 at 22:35

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

3 Comments

"Don't try to translate pointer manipulation code to C#" - agreed, but in the future: the new Span<T> stuff allows direct coercion of spans between different T, which makes this kind of stuff so cute, without needing any unsafe
@MarcGravell: Indeed, I agree. My intention here was to describe how to solve the general problem from first principles, rather than to solve the specific problem using cool new stuff that's not fully baked yet.
and it always impresses me how well you express that key aim - "write/ask what you're trying to do, not how you're trying to do it" - once you've done that: most things fade away into implementation minutae
1

Essentially:

        ushort[] hv = new ushort[4];
        byte[] h1 = new byte[16];

        for (int i = 0; i < 4; i++)
        {
            // note: this call is CPU-endian; if your data is not CPU-endian,
            // you will need to write a known-endian op - aka "shift" and "or"
            hv[i] = BitConverter.ToUInt16(h1, i * 2);
        }

Although I wonder if a blit might be more appropriate.

Note that you can also use unsafe C# code to have essentially the same code as the C code (via fixed), and in the upcoming bits: this would be a good fit for Span<T> which allows for simple thunks between different T.

3 Comments

After some twinkling around, i got this almost finished, how would you port hv[i] = *(uint16_t *)(h1 + 8 + i*2); to C#?
@Varreza the *(uint16_t *) is the BitConverter.ToUInt16, where h1 is the vector (array) and 8 + i*2 is the offset. So literally the only thing that changes is the second parameter to ToUInt16
Perfect! Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.