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)
这是我的错误代码和操作字节索引的正确方法吗?
问题是:
演员阵容是否预计会结束
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]。
值类型转换的文档说:
结果值是通过转换括号中的表达式获得的。如果指定类型的大小与表达式的大小不同,这可能涉及截断或扩展。表达式的符号始终被保留。