这是C#中的GetHashCode32方法的代码:
public static class StringHelper
{
public static unsafe int GetHashCode32(this string s)
{
fixed (char* str = s.ToCharArray())
{
char* chPtr = str;
int num = 0x15051505;
int num2 = num;
int* numPtr = (int*)chPtr;
for (int i = s.Length; 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;
}
return (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;
}
c代码在-m32模式下编译。
但是这两个功能有不同的输出
当输入为“ 354707043566597”时
我的c代码输出为637077169,而在GetHashCode32()中应该为-1744455423。
GetHashCode32是C#的库方法。所以是对的。但是我不知道我的C代码有什么问题。
谢谢!
最佳答案
我可以给你一些原因,为什么它可能会有所不同:
首先,0x15051505
== 0b10101000001010001010100000101
,如果您计算的话,它是29位长。假定sizeof(int) <= 4
,按C标准左移5会产生不确定的行为。
其次,这一行:
int *numPtr = (int*)chPtr;
可能是在C版本中搞砸了(我不知道C#如何处理指针,所以我不能在那说)。当您执行
numPtr += 2;
时,将其作为char*
而不是int*
完全不同(一个将其移动2个字节,另一个将其移动2 * sizeof(int)
个字节。因此,实际上是在取消引用内存超出字符串范围(假设sizeof(int) == 4
),再次导致未定义的行为。