Reputation: 117
I'm having MAJOR difficulties with this modulo. The C version outputs what I want but not the correct value. My C# outputs what I don't want, but the correct value. How can I get C# version to output C version?
C
typedef unsigned long long u64;
typedef unsigned char u8;
static u64 pfd_calculate_hash_table_entry_index(const char *file_name) {
u64 hash, len, i;
if (!file_name)
return -1;
len = strlen(file_name);
hash = 0;
for (i = 0; i < len; ++i)
hash = (hash << 5) - hash + (u8)file_name[i];
printf( "%X ", hash);
printf( "mod ");
printf( "%X ", 0x39);
printf( "= %X\n", hash % 0x39 );
return hash % 0x39;
}
C#
public ulong pfd_calculate_hash_table_entry_index(char[] file_name)
{
uint hash, len, i;
hash = 0;
len = (uint)Array.IndexOf(file_name, '\0');
for (i = 0; i < len; ++i)
hash = (hash << 5) - hash + (byte)file_name[i];
MessageBox.Show(hash.ToString("X") + " mod 0x39 = " + (hash % 0x39).ToString("X"));
return ((ulong)hash % 0x39);
}
C#
#1: char[] file_name = "PARAM.SFO";
#2: char[] file_name = "RAGE.SAV"
C
#1: char* file_name = "RAGE.SAV";
#2: char* file_name = "PARAM.SFO"
C Hashes
#1: 0x319FFDA7
#2: 0x1A8C4B5B
C# Hashes
#2: 0x319FFDA7
#1: 0x1A8C4B5B
C Output
#1: 0x319FFDA7 % 0x39 = 0x21;
#2: 0x1A8C4B5B % 0x39 = 0x8;
C# Output
#1: 0x319FFDA7 % 0x39 = 0xA;
#2: 0x1A8C4B5B % 0x39 = 0xE;
pics...
C
C#
Upvotes: 0
Views: 118
Reputation: 1502186
Okay. As I thought, this is a problem with the mismatch between u64
in C and uint
in C#, which is then confused by bad diagnostic code in the C version.
This is easy to demonstrate in a short but complete C# program:
using System;
public class Test
{
static void Main()
{
ShowHash("PARAM.SFO");
ShowHash("RAGE.SAV");
}
static void ShowHash(string name)
{
uint hash = 0;
foreach (char c in name)
{
hash = (hash << 5) - hash + (byte) c;
}
Console.WriteLine("0x{0:X} mod 0x39 = {1:X}", hash, hash % 0x39);
}
}
Output:
0x1A8C4B5B mod 0x39 = E
0x319FFDA7 mod 0x39 = A
Change the type of hash
from uint
to ulong
and we get:
0x3FC01A8C4B5B mod 0x39 = 8
0x21B319FFDA7 mod 0x39 = 21
So to get the right modulus, you don't want the value 0x1A8C4B5B - you want 0x3FC01A8C4B5B. If you had written a short but complete C program which actually started off with 0x1A8C4B5B, you'd have seen it give the same result as the C# code.
As another point, this code is pretty much assuming ASCII filenames... is that definitely going to be valid for you?
Upvotes: 2