1

Delphi XE2,简单代码:

function FastSwap(Value: uint16): uint16; register; overload;
asm
  bswap eax
  shr eax, 16
end;
...
type
  PPicEleHdr = ^TPicEleHdr;

  TPicEleHdr = packed record
    zero, size, count: word;
  end;
var
  count: integer;
  buf: TBytes;
begin
...
  peh := @buf[offs];
  count := integer(FastSwap(peh.count));
  for i := 0 to count - 1 do begin

在这里for我在 CPU 窗口中看到

UnitExtract.pas.279: for i := 0 to count - 1 do begin
0051E459 8B45DC           mov eax,[ebp-$24]
0051E45C 48               dec eax
0051E45D 85C0             test eax,eax
0051E45F 0F82CD000000     jb $0051e532
0051E465 40               inc eax
0051E466 8945AC           mov [ebp-$54],eax
0051E469 C745F400000000   mov [ebp-$0c],$00000000

因此,当计数0没有正常工作时,test eax, eax(eax = $FFFFFFFF after dec eax)在通过进位标志执行时不会影响进位jb标志。使用中有什么我不明白的地方for吗?

4

2 回答 2

7

如所写,这不会编译,因为您没有i.

但是我的心理调试感觉说它在i某处被声明为cardinal(无符号整数),因此当它尝试评估时0 - 1,它得到的MAXINT不是-1,因为无符号整数不能表示负值。

如果无符号整数有可能变为负数,则永远不应使用无符号整数作为for循环的索引变量或边界变量。否则,你会得到这样的错误。事实上,您一般不应该使用无符号整数。它们并不像看起来那么有用(如果您需要一个大于最大有符号值的值,那么您最终可能需要一个高于该值两倍的值,所以您真正需要的是下一个更大的整数大小),它们往往会导致像这样的奇怪错误。

于 2013-05-23T13:25:25.030 回答
7

通过逆向工程,我推断这i是一个无符号的 32 位整数,Cardinal. 因此编译器for在无符号上下文中执行循环算术。这意味着它Count-1被解释为无符号,所以你的循环从0to运行high(i)

为了充实这一点,这是一步一步发生的:

  • Count$00000000
  • Count-1被评估并具有价值$FFFFFFFF
  • 解释为无符号整数$FFFFFFFF是 2 32 -1。
  • 您的循环体针对所有值 0 <= i < 2 32执行。

解决方案是使您的循环变量为有符号整数,例如Integer.

当您切换i为 typeInteger时,会发生以下情况:

  • Count$00000000
  • Count-1被评估并具有价值$FFFFFFFF
  • 解释为有符号整数$FFFFFFFF是 -1。
  • 循环体不执行。
于 2013-05-23T13:23:39.510 回答