# C# Unsafe code translation?

I have some code that I'm using in a standard C# application. I'm sharing the library in a silverlight project that doesn't allow unsafe code. I don't know much at all about unsafe/pointer logic/arethmetic and was wondering if someone could translate the following code snippet so that it will run without /unsafe. I don't care about the performance drop since the code won't be called often on the client. Thanks in advance for any assistance.

public static unsafe int GetStableHash(string name)
{
fixed (char* str = name)
{
char* chPtr = str;
int num = 352654597;
int num2 = num;
int* numPtr = (int*)chPtr;
for (int i = name.Length; i > 0; i -= 4)
{
num = (((num << 5) + num) + (num >> 27)) ^ numPtr[0];
if (i <= 2)
{
break;
}
num2 = (((num2 << 5) + num2) + (num2 >> 27)) ^ numPtr[1];
numPtr += 2;
}
return (num + (num2 * 1566083941));
}
}


@JeffMercado Thanks again for your time here guys. I appreciate it. I've tried your updated version and now I get the exception on line

num = (((num << 5) + num) + (num >> 27)) ^ BitConverter.ToInt32(bytes, j + 0);


The test code I'm using is

string[] tmp = new string[]
{
"Hello",
"Isn't that Æegis over there?",
"Isn't that something",
"11111111111",
"111",
"112"};
foreach (string s in tmp)
{
int one = GetStableHash(s);
int two = GetStableHashSafe(s);

System.Diagnostics.Debug.WriteLine(one + " : " + two + " == " + (one == two).ToString());
}

-
Questions such as this belongs on Stack Overflow, not here. Fortunately the translation should be simple. –  Jeff Mercado Jan 11 '12 at 6:18
When I posted this question on Stack Overflow, I was told to post it here. Thanks though. –  user1142433 Jan 11 '12 at 6:24
Really? Well I may be wrong but this site is for reviews and optimizations, not to get translations AFAIK. –  Jeff Mercado Jan 11 '12 at 6:29
Understood. It's just hard to know ahead of time sometimes. Thanks again. –  user1142433 Jan 11 '12 at 6:43

This should be pretty much equivalent if I'm not mistaken.

public static int GetStableHashSafe(string name)
{
var bytes = Encoding.Unicode.GetBytes(name + "\0"); //HACK: need null terminator for odd counts
int num = 0x15051505;
int num2 = num;
int j = 0;
for (int i = name.Length; i > 0; i -= 4)
{
num = (((num << 5) + num) + (num >> 27)) ^ BitConverter.ToInt32(bytes, j + 0);
if (i <= 2) break;
num2 = (((num2 << 5) + num2) + (num2 >> 27)) ^ BitConverter.ToInt32(bytes, j + 4);
j += 8;
}
return (num + (num2 * 0x5D588B65));
}

-
Hopefully I'm not misunderstanding how the conversion works from string to char*. I'm assuming it's just a simple reinterpretation of the bytes untouched as if the characters are 8-bits in size (as it is in C). –  Jeff Mercado Jan 11 '12 at 6:46
I think that j += 2; should be j += 8; –  Mike Nakis Jan 11 '12 at 6:53
Ah yes, you're right. –  Jeff Mercado Jan 11 '12 at 6:57
Also, I think that int i = bytes.Length; should be int i = name.Length; –  Mike Nakis Jan 11 '12 at 7:02
user: ah yes, I am not sure whether the author of the original unsafe function did this on purpose or by accident, but his code relies on the under-documented fact that strings in C# are zero-terminated so as to facilitate passing them directly to unmanaged functions without having to append a zero character. So, if the string has an odd length, the unmanaged function overshoots and includes the terminator in the calculation. It does not throw an out of range exception because it is unsafe. So, of course you need to emulate that behavior in order to produce the exact same result. Bummer. –  Mike Nakis Jan 11 '12 at 14:24