核心提示:群友探讨到这个问题顺便有空分析了下delphi编译器的实现方式,有错误地方敬请指出。function AnsiStrInCharSet(ch: char; CharSet: TSysCharSet):...
群友探讨到这个问题顺便有空分析了下delphi编译器的实现方式,有错误地方敬请指出。function AnsiStrInCharSet(ch: char; CharSet: TSysCharSet): boolean;
begin
Result := ch in CharSet;
end;
测试调用:if AnsiStrInCharSet('a', ['a'..'z']) then ...
实际编译器翻译为以下代码:
0045BF7A |. F3:A5 rep movs dword ptr es:[edi], dword ptr [esi] ;
复制ESI( ['a'..'z']) 到BT指令标志判断dest操作数,也就是CharSet: TSysCharSet 的内容由编译器固定编译为一个位信息常量,该常量长度为32byte,定义结构为:
TBitInfoField =array [0..7] of dword;
暂称该常量为BitInfoField:TBitInfoField 具体规则后面讲述。
0045BF7C |. 0FB6C0 movzx eax, al ;
赋值到BT指令标志判断src操作数,也就是ch: char
0045BF7F |. 0FA345 E0 bt dword ptr [ebp-20], eax ;
[ebp-20] 实际指向BitInfoField,eax是位数,作用就是把BitInfoField的第eax位送CF标志
比如['a'..'z']编译器编译的BitInfoField为:
0012F588 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF 07 ............?�
0012F598 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[#0..#255]编译器编译的BitInfoField为:
0012F588 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ��������������
0012F598 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ����������������
为什么编译器会这么编译呢?因为bt指令是一个标志测试指令具体语法格式为:
BT r/m16,r16
将所选的位存储到 CF 标志
BT r/m32,r32
将所选的位存储到 CF 标志
BT r/m16,imm8
将所选的位存储到 CF 标志
BT r/m32,imm8
将所选的位存储到 CF 标志
这里有两个公式确定位值:
1. BIdx= BitOffset div 32
2. BBit= BitOffset mod 32
我们这里的in编译器使用的是 BT m32,r32格式,它的作用就是把m32内存中BitInfoField[BIdx(r32)]常量的数据的第BitInfoField[BBit(r32)]位送CF标志.
假设枚举范围是['a'..'z'] 则BitInfoField为:
00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF 07
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
'a' in ['a'..'z'] 最后转换成的CPU指令应该是:
bt dword ptr [BitInfoField] , eax ; eax= $61
因为 'a'的Ascll码为:$61 根据公式: BIdx = $61 div 32 = 3 , BBit= BitOffset mod 32 =1
BitInfoField[BIdx=3 ] = $7FFFFFE 转换为二进制为:00000111111111111111111111111110
BBit = 1
00000111111111111111111111111110
31-------------------------------0
那么 bt dword ptr [BitInfoField] , $61 就是把下面标志传送到CF标志寄存器
000001111111111111111111111111[1]0
31-------------------------------0
所以CF =1
这样就完成了'a' in ['a'..'z'] 的判断。
根据此原理可以推导出 delphi的 char in ['a'..'z'] 和 char in ['a'..'z','1'..'9'] 执行效率是一样的
因为['a'..'z','1'..'9'] 的BitInfoField为:
00 00 00 00 00 00 FE 03 00 00 00 00 FE FF FF 07
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
当判断任意字符 bt dword ptr [BitInfoField] , BitOffset
通过公式:
1. BIdx= BitOffset div 32
2. BBit= BitOffset mod 32
计算出BIdx 和BBit 只需把相应标志位传送到CF即完成。
总结DELPHI in 操作效率比pos操作效率要高很多,并且效率不被枚举元素个数和多少影响,缺点是只能判断0-255范围的数据。