user1594121
user1594121

Reputation: 117

Modulous errors Help C C#

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

http://puu.sh/3dT5L/52ababeccf.png

C#

http://puu.sh/3dT6P/62b911c102.png

Upvotes: 0

Views: 118

Answers (1)

Jon Skeet
Jon Skeet

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

Related Questions