2025年10月22日 星期三  乙巳年 九月初二 【蛇】丙戌月 甲子日
用户名: 密 码: 保存
您现在的位置:首页 >> 基础算法 >> window基础 >> 内容

深入剖析Delphi中IN操作符实现原理(编译)

时间:2011/9/3 15:28:00 点击: 2332

  核心提示:群友探讨到这个问题顺便有空分析了下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范围的数据。

作者:codegame 来源:转载
惊讶 欠揍 支持 很棒 愤怒 搞笑 恶心 不解
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
  • 盒子文章 技术支持:深圳市麟瑞科技有限公司(www.2ccc.com) © 2025 版权所有 All Rights Reserved.
  • 粤ICP备10103342号-1