Delphi XE字节数组索引

Mic*_*lev 6 arrays delphi indexing bytebuffer compiler-bug

我像这样使用简单的循环缓冲区

var
  Values: array [byte] of single;
  ptr: byte;
Run Code Online (Sandbox Code Playgroud)

在这个测试例子中

for ptr:=0 to 10 do Values[Byte(ptr-5)]:=1;
Run Code Online (Sandbox Code Playgroud)

我希望设置为1前5个值和最后5个值,但XE4 compiller产生不正确的代码,它使用32位指针数学来计算数组索引:

for ptr:=0 to 10 do Values[Byte(ptr-5)]:=1;
005B94BB C645FB00         mov byte ptr [ebp-$05],$00
005B94BF 33C0             xor eax,eax
005B94C1 8A45FB           mov al,[ebp-$05]
005B94C4 C78485E0FBFFFF0000803F mov [ebp+eax*4-$0420],$3f800000
005B94CF FE45FB           inc byte ptr [ebp-$05]
005B94D2 807DFB0B         cmp byte ptr [ebp-$05],$0b
005B94D6 75E7             jnz $005b94bf
Run Code Online (Sandbox Code Playgroud)

这是我的错误代码和操作字节索引的正确方法吗?

LU *_* RD 4

问题是:

演员阵容是否预计会结束Byte()

让我们将反汇编与溢出检查开/关进行比较。

{$Q+}
Project71.dpr.21: for ptr:= 0 to 10 do Values[Byte(ptr-5)]:= 1;
0041D568 33DB             xor ebx,ebx
0041D56A 0FB6C3           movzx eax,bl
0041D56D 83E805           sub eax,$05
0041D570 7105             jno $0041d577
0041D572 E82D8DFEFF       call @IntOver
0041D577 0FB6C0           movzx eax,al
0041D57A C704870000803F   mov [edi+eax*4],$3f800000
0041D581 43               inc ebx
0041D582 80FB0B           cmp bl,$0b
0041D585 75E3             jnz $0041d56a

{$Q-}
Project71.dpr.21: for ptr:= 0 to 10 do Values[Byte(ptr-5)]:= 1;
0041D566 B30B             mov bl,$0b
0041D568 B808584200       mov eax,$00425808
0041D56D C7000000803F     mov [eax],$3f800000
0041D573 83C004           add eax,$04
0041D576 FECB             dec bl
0041D578 75F3             jnz $0041d56d
Run Code Online (Sandbox Code Playgroud)

使用{$Q+}换行可以工作,而使用{$Q-}换行则不起作用,并且在{$R+}设置时编译器不会为错误的数组索引生成范围错误。

因此,对我来说,结论是:由于range check on数组索引越界不会生成运行时错误,因此预计会出现换行

当溢出检查打开时进行换行这一事实进一步证明了这一点。


这应该被报告为编译器中的错误。

完成: https: //quality.embarcadero.com/browse/RSP-15527 “数组索引内的类型转换失败”


注意:@Rudy 在他的回答中给出了解决方法。


附录:

以下代码:

for ptr:= 0 to 10 do WriteLn(Byte(ptr-5));
Run Code Online (Sandbox Code Playgroud)

生成:

251
252
253
254
255
0
1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

适用于范围/溢出检查的所有组合。

同样,Values[Byte(-1)] := 1;为所有编译器选项将 1 分配给 Values[255]。


值类型转换的文档说:

结果值是通过转换括号中的表达式获得的。如果指定类型的大小与表达式的大小不同,这可能涉及截断或扩展。表达式的符号始终被保留。