我正在追踪第 3 方代码深处的错误,其中声明
fStringLen := Str - fToIdent;
给出运行时错误,其中:
Str
是PChar私有函数参数,此时为''nil {%0}
:目前还不清楚是否有任何事情追踪所有事件,看起来好像没有对
fToIndent
PChar 属性 我们的软件有一个较旧的 32 位版本和较旧版本的 3rd 方软件,但该代码段是相同的。如果我运行代码,这些值是相同的,但不会出现范围检查错误。
FWIW,这是代码,请参阅最后一条语句:
function TdaSynHighlighterSQL.HashKey(Str: PChar): Integer;
// called with Str = 'absolute'
function GetOrd: Integer;
begin
case Str^ of
'_': Result := 1;
'a'..'z': Result := 2 + Ord(Str^) - Ord('a');
'A'..'Z': Result := 2 + Ord(Str^) - Ord('A');
'@':
if fDialect in [sqlMSSQL7, sqlMSSQL2K] then
Result := 24
else
Result := 0;
else Result := 0;
end;
end;
begin
Result := 0;
while IsIdentChar(Str^) do // Always true until Str=''
begin
Result := (2 * Result + GetOrd) and $FFFFFF;
inc(Str);
end;
Result := Result and $FF; // 255
fStringLen := Str - fToIdent;
end;
如何最好地解决这个问题?
我觉得很奇怪,这个代码仍然不是 64 位证明
问题是由使用 while 循环引起的。在执行
fStringLen := Str - fToIdent;
时,它已经指向超过字符串长度的内存,这会导致范围检查错误。
考虑这个简单的 while 循环示例,其中我有简单的整数作为控制值。
while I < 10 do
begin
Memo1.Lines.Add('LoopN: ' +IntToStr(I));
Inc(I,1);
end;
Memo1.Lines.Add('Value of I after loop is: '+IntToStr(I));
您可能期望 while 循环结束后控制变量
I
的值将为 9,但事实并非如此。事实上是10。为什么呢?
这是因为整个循环在每个循环开始之前检查控制变量的值。但我在上一个循环周期中增加了控制变量的值超过了所需的范围。
因此,您可能需要在增加
Str
的值之前计算循环内的 fStringLen。
while IsIdentChar(Str^) do // Always true until Str=''
begin
Result := (2 * Result + GetOrd) and $FFFFFF;
fStringLen := Str - fToIdent;
inc(Str);
end;
但是,这将导致字符串中的每个字符的
fStringLen
被更新。
如果您想避免这种情况并在循环后仍然计算
fStringLen
,则需要将 Str
的值减少 1,以便它显示到字符串中最后一个字符的位置。