以下是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代码有什么问题。 谢谢!
答案 0 :(得分:1)
我可以告诉你为什么它可能会有所不同:
首先,0x15051505
== 0b10101000001010001010100000101
,如果算一算,则为29位长。如果将sizeof(int) <= 4
假设为int *numPtr = (int*)chPtr;
,则按5的左移将产生未定义的行为。
其次,这一行:
numPtr += 2;
可能在C版本中搞砸了(我不知道C#如何对待指针,所以我不能说那里)。执行char*
时,将其视为int*
而不是2 * sizeof(int)
(一个将移动2个字节,另一个移动sizeof(int) == 4
个字节时,这完全不同因此,您实际上是取消引用超出字符串范围的内存(假设{{1}}),再次导致未定义的行为。
答案 1 :(得分:0)
C char是1个字节,并且是带符号的,C#char是2个字节,而在C#中,第一个字节是无符号的。
这意味着,如果您在内存中有一个字符串并使用4字节的int poitner访问该内存,则在C中将4个字符转换为一个int,而在C#中将2个字符转换为一个int。因此,这永远不会产生相同的结果。
如何解决::在C中使用数据类型wchar_t,它应该更接近C#的char。您可以使用{print}
从控制台直接读取到wscanf
缓冲区。
答案 2 :(得分:-1)
问题在于,原始算法一次从内存中读取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语言中提供的数据不同(并且不正确):
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]) ""
一种快速的解决方案是将numPtr
强制转换为char
(而不是int
),并手动构造期望的格式以保持哈希兼容性。请记住,本机的GetHashCode甚至不是完全确定性的-Visual Studio和Mono对相同的输入产生不同的结果。