C# 为什么字符串GetHashCode只处理每四个字符?

C# 为什么字符串GetHashCode只处理每四个字符?,c#,algorithm,hash,C#,Algorithm,Hash,我一直在读,因为它是由。我试图真正理解散列是如何工作的,以及为什么Jon如此喜欢他提供的算法。我还没有声明对此有答案,但我确实有一个关于System.String实现GetHashCode的具体问题 考虑一下代码,重点放在带注释的 为什么他们只处理每四个字符?如果你愿意,他们为什么从右到左处理 他们也没有这样做。它们将字符作为整数值对进行处理(注意,它们在while循环中使用*numPtr和numPtr[1])。两个Int32值占用的空间与4个字符相同,这就是它们每次从长度中减去4的原因 这是从

我一直在读,因为它是由。我试图真正理解散列是如何工作的,以及为什么Jon如此喜欢他提供的算法。我还没有声明对此有答案,但我确实有一个关于
System.String
实现
GetHashCode
的具体问题

考虑一下代码,重点放在带注释的

为什么他们只处理每四个字符?如果你愿意,他们为什么从右到左处理

他们也没有这样做。它们将字符作为整数值对进行处理(注意,它们在while循环中使用
*numPtr
numPtr[1]
)。两个
Int32
值占用的空间与4个字符相同,这就是它们每次从长度中减去4的原因


这是从前到后(按数组顺序)处理的,但长度会递减,因为它表示要处理的字符串的剩余长度。这意味着他们在可能的情况下一次从左到右处理“4个字符的块”。

它不会处理每四个字符。这是因为这一行:

int* numPtr = (int*) chPtr;
它将指针类型更改为
int*
,这使得它每次使用
numPtr
时都会处理两个
char
s。因为它在每个循环迭代中使用两次:

num1 = (num1 << 5) + num1 + (num1 >> 27) ^ *numPtr;
num2 = (num2 << 5) + num2 + (num2 >> 27) ^ numPtr[1];
num1=(num1>27)^*numPtr;
num2=(num2>27)^numPtr[1];

每次需要4个字符。

numPtr
是指向32位整数的指针。
循环的每次迭代处理两个32位整数(
*numPtr
numPtr[1]


因此,它以
numPtr+=2
(跳过2个32位块)和
length-=4
(我们刚刚完成4个16位
char
s)结束。

循环展开。我在中明确地介绍了这个细节。作为旁注:在他的书C#depth,第三版中,他简单地将第一项的hashcode乘以37,然后添加第二项的hashcode(在一个有2个字段的类中)。不过,他提到了有效的Java 2以获取更多信息,很遗憾我没有。@HansPassant,我不得不说,第一行,
这可能比您所期望的要多…
,从代码的角度来看是正确的。然而,你的答案是荒谬的现象!它确实帮助我更好地理解了这个操作,我很抱歉重复了一点。所以这个操作,
(int*)chPtr
,将整个
char[]
转换为32位整数?或者更确切地说,是指向32位整数的指针?为什么它必须是指针?伙计,我已经很久没有使用指针了(嗯,大概10年了)。@MichaelPerrenoud:没有。指针指向原始内存。将
X*
强制转换为
Y*
会告诉编译器将原始内存视为
Y
而不是
X
。这不一定是安全的。当你使用指针时,它会更快。如果没有指针,你不能将
char[]
转换成
int[]
@SLaks或@Marcin,我可以阅读哪些材料来帮助我更好地理解指针?此外,为什么将
char*
转换为
int*
需要两个字符?我相信我对它的理解非常初级,但我想更好地理解它,不想浪费你的时间,因为你显然有非常深刻的理解。@MichaelPerrenoud:
char
有2个字节宽
int
是4字节宽。因此,
int*
引用该地址的前4个字节。我说的对吗,这基本上就是他们在这里做的事情?我知道帖子在
C
,但我是否走上了更好理解的正确道路?@MichaelPerrenoud Yep-指针数学在C#中并不常见(需要
不安全的
),但你可以在必要时做。非常感谢!我可以看到我在这里有一个真正的缺陷,所以我要做一些阅读和建立一些例子。在开始构建示例时,我可能会有一些后续问题,您可能会看到。@MichaelPerrenoud如果您是托管开发人员,这并不是一个真正的缺陷-使用不安全和操纵指针是一个好主意,这是非常非常罕见的;)哈哈,这是一个非常好的观点!我想我只是有空间在计算机科学的这些较低层次的部分成长!
num1 = (num1 << 5) + num1 + (num1 >> 27) ^ *numPtr;
num2 = (num2 << 5) + num2 + (num2 >> 27) ^ numPtr[1];