C# 在C中重写GetHashCode32(字符串s)方法

C# 在C中重写GetHashCode32(字符串s)方法,c#,c,hashcode,C#,C,Hashcode,下面是C#中GetHashCode32方法的代码: 公共静态类StringHelper { 公共静态不安全int GetHashCode32(此字符串为s) { 已修复(char*str=s.ToCharArray()) { char*chPtr=str; int num=0x15051505; int num2=num; int*numPtr=(int*)chPtr; 对于(int i=s.长度;i>0;i-=4) { num=((num>0x1b))^numPtr[0]; 如果(i 0x1b

下面是C#中GetHashCode32方法的代码:

公共静态类StringHelper
{
公共静态不安全int GetHashCode32(此字符串为s)
{
已修复(char*str=s.ToCharArray())
{
char*chPtr=str;
int num=0x15051505;
int num2=num;
int*numPtr=(int*)chPtr;
对于(int i=s.长度;i>0;i-=4)
{
num=((num>0x1b))^numPtr[0];
如果(i 0x1b))^numPtr[1];
numpr+=2;
}
返回值(num+(num2*0x5d588b65));
}
}
}
我用C语言重写了这个方法,如下所示:

#include <stdio.h> 
#include <string.h> 

int main()           
{                  
    char    str[320+1];      
    memset(str, 0, sizeof(str));
    int     i;              
    scanf("%s", str);

    char *chPtr = str;
    int num = 0x15051505;
    int num2 = num;
    int *numPtr = (int*)chPtr;

    for (i = strlen(str); i > 0; i -= 4) {
        num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
        if (i <= 2)
        {       
            break;
        }                 
        num2 = ( ( (num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
        numPtr += 2;
    } 
    printf("hash code: %d\n", num + (num2 * 0x5d588b65));
    return 0;
}
#包括
#包括
int main()
{                  
char-str[320+1];
memset(str,0,sizeof(str));
int i;
scanf(“%s”,str);
char*chPtr=str;
int num=0x15051505;
int num2=num;
int*numPtr=(int*)chPtr;
对于(i=strlen(str);i>0;i-=4){
num=((num>0x1b))^numPtr[0];
如果(i 0x1b))^numPtr[1];
numpr+=2;
} 
printf(“哈希代码:%d\n”,num+(num2*0x5d588b65));
返回0;
}
c代码在-m32模式下编译。 但这两个函数有不同的输出

当输入为“354707043566597”时

我的c代码输出是637077169,而在GetHashCode32()中它应该是-1744455423

GetHashCode32是C#的库方法。所以这是正确的。但是我不知道我的C代码出了什么问题。
谢谢

我可以给你一些不同的理由:


首先,
0x15051505
==
0b10101000000101000101010000001
,如果您计算它,它的长度是29位。根据C标准,左移5将产生未定义的行为,假设
sizeof(int)问题是原始算法从内存中读取UTF-16(Unicode)字符串,一次两个

预期数据用零填充:

0x00350033 (numPtr[0]) lp0: "35"
0x00370034 (numPtr[1])      "47"
0x00370030 (numPtr[0]) lp1: "07"
0x00340030 (numPtr[1])      "04"
0x00350033 (numPtr[0]) lp2: "35"
0x00360036 (numPtr[1])      "66"
0x00390035 (numPtr[0]) lp3: "59"
0x00000037 (numPtr[1])      "7"
C中提供的数据不同(且不正确):


一个快速的解决方案是将
numPtr
转换为
char
(而不是
int
),并手动构造期望的格式以保持哈希兼容性。请记住,本机GetHashCode甚至不是完全确定的——VisualStudio和Mono为相同的输入生成不同的结果

C char是1字节,它是有符号的,C#char是2字节,在C#中,第一个字节是无符号的

这意味着,如果内存中有一个字符串,并使用一个4字节的int poitner来访问该内存,那么一个int中会有4个C字符,但一个int中只能有2个C#字符。因此,这永远不会产生相同的结果


如何修复:在C中使用数据类型wchar\u t,它应该更接近C的char。您可以使用
wscanf
从控制台直接读取到
wchar\t
缓冲区。

我为什么要这样做?谢谢您这么快的回答。我也注意到你的第二点。我发现在C中,一个字符实际上是两个字节。实际上,在C中,一个字符是两个字节。因此,循环是正确的。:-)@唐纳,我的回答有问题吗?请留下评论,我会修正它。我尽力调查产出差异的原因,并提出了一个可能的解决方案。但你的否决票没有告诉我什么。
int *numPtr = (int*)chPtr;
0x00350033 (numPtr[0]) lp0: "35"
0x00370034 (numPtr[1])      "47"
0x00370030 (numPtr[0]) lp1: "07"
0x00340030 (numPtr[1])      "04"
0x00350033 (numPtr[0]) lp2: "35"
0x00360036 (numPtr[1])      "66"
0x00390035 (numPtr[0]) lp3: "59"
0x00000037 (numPtr[1])      "7"
0x37343533 (numPtr[0]) lp0: "3547"
0x34303730 (numPtr[1])      "0704"
0x36363533 (numPtr[0]) lp1: "3566"
0x00373935 (numPtr[1])      "597"
0x00000000 (numPtr[0]) lp2: ""
0x00000000 (numPtr[1])      ""
0x00000000 (numPtr[0]) lp3: ""
0x00000000 (numPtr[1])      ""