delphi 为什么BobJenkinsHash函数在这种情况下返回范围错误?

d7v8vwbk  于 2023-10-18  发布在  Jenkins
关注(0)|答案(1)|浏览(127)

在FPC Lazarus下,我使用下面的函数来计算字符串的哈希值,这是用来保存字典中的对象:

function MyClass.HashCode(): UInt32;
var
  keyStr: string;
begin
  keyStr := KeyToString();
  Result := BobJenkinsHash(keyStr[1], Length(keyStr) * SizeOf(Char), 0);
end;

此函数有时会抛出错误:
项目< Name >引发了异常类“RunError(201)”,消息为:
范围检查错误
在文件< source >第行< Line >:
结果:= BobJenkinsHash(keyStr[1],Length(keyStr)* SizeOf(Char),0);
这在一些用法之后连贯地发生。我不确定是否有一些特定的字符串或使用次数。举例来说:“Button_logo”似乎会引发此错误。
我找不到(不幸的是)相关的文件:我没有发现FPC和 Delphi 文档的文档(因为大多数时间)无关。

iibxawm4

iibxawm41#

我不知道这是否适用于FreePascal,但在 Delphi 中,BobJenkinsHash()函数(顺便说一句,该函数已被弃用)返回一个 * 有符号 * Integer

function BobJenkinsHash(const Data; Len, InitData: Integer): Integer;
                                                             ^^^^^^^

您将返回值赋给 unsignedUInt32。如果函数返回负值(参见Can result of BobJenkinsHash function be negative?),则在启用了范围检查的情况下,您将获得运行时错误。
这个问题同样存在于 Delphi 中的后继函数THashBobJenkins.GetHashValue()中。
因此,您可以:

function MyClass.HashCode(): UInt32;
var
  keyStr: string;
begin
  keyStr := KeyToString();
  {$IFOPT R+} {$RANGECHECKS OFF} {$DEFINE RC_WAS_ON} {$ENDIF}
  // or: {$IFOPT R+} {$R-} {$DEFINE RC_WAS_ON} {$ENDIF}
  // or: {$PUSH} {$R-} (FPC only)
  Result := BobJenkinsHash(PChar(keyStr)^, Length(keyStr) * SizeOf(Char), 0);
  {$IFDEF RC_WAS_ON} {$RANGECHECKS ON} {$UNDEF RC_WAS_ON} {$ENDIF}
  // or: {$IFDEF RC_WAS_ON} {$R+} {$UNDEF RC_WAS_ON} {$ENDIF}
  // or: {$POP} (FPC only)
end;
  • 在将BobJenkinsHash()的返回值赋给UInt32之前,先对它进行类型转换:
function MyClass.HashCode(): UInt32;
var
  keyStr: string;
begin
  keyStr := KeyToString();
  Result := UInt32(BobJenkinsHash(PChar(keyStr)^, Length(keyStr) * SizeOf(Char), 0));
end;
  • HashCode()方法的返回类型更改为Integer
function MyClass.HashCode(): Integer;
var
  keyStr: string;
begin
  keyStr := KeyToString();
  Result := BobJenkinsHash(PChar(keyStr)^, Length(keyStr) * SizeOf(Char), 0);
end;

相关问题