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范围的数据。
86 个解决方案
#1
顶。。。。。
#2
不懂汇编,牛人.
#3
in跟pos的应用范围不一样,硬拿他们比较没有意义
#4
不是比较,是弄清楚编译器实现in的本质。
#5
#6
来句庸俗的."华丽的插入前十!"
#7
#8
我是个菜鸟 Delphi是开发语言还是开发环境啊
#9
我只是路过看看的。
#10
当范围小的时候应该会更快,比如如果是 in [0..7],后面那个 set 常量只会占用一个字节
#11
支持一下!
#12
如果是直接死值那么的确是占用更小
但如果是使用我上面那个函数
function AnsiStrInCharSet(ch: char; CharSet: TSysCharSet): boolean;
begin
Result := ch in CharSet;
end;
那么
AnsiStrInCharSet(‘’,[0..n])这种方式的话是一样的,那个常量还是32byte
#13
上面说错了,如果是直接死值那么in的实现方式又是另一种,不使用bt指令所以不存在那个常量值
#14
中国很少有用DELPHI
#15
相信Delphi能再造辉煌。顶顶顶顶顶!
#16
这个是什么,好复杂啊
#17
#18
好帖。
#19
支持一下!
#20
晕,没看懂~
#21
#22
回帖有分拿、、、
#23
虽然看不懂,还是顶顶,赚分吧
#24
学习学习
#25
#26
#27
学习学习 顶顶
#28
顶你!~~!
#29
谢谢~~!
#30
..............
#31
不错 不错 非常不错 哈哈
#32
我相信你是分析完了, 但是你的写法只会让初学的人一头雾水. 建议这样的文章应该写的通俗易懂些, 才能给大家分享
#33
楼上说的很有道理,我就是初学者!
#34
我还能看得懂,就是排版比较凌乱。
#35
啊三是事实是事实是事实是事实是事实是事实是事实是事实收拾收拾
#36
学习!!!
#37
学习学习
#38
#39
#40
讲得太深了
#41
来句庸俗的."华丽的插入前十!"
#42
每天回帖即可获得10分可用分!
#43
每天回帖即可获得10分可用分!
#44
每天回帖即可获得10分可用分!
#45
其实,我想要5分,下载 CFS 视频破解器。。给我分吧
#46
不懂汇编
#47
学习支持那份
#48
好好。。。。。。。
#49
每天回帖即可获得10分可用分!
#50
是很好的东西!!!1
#1
顶。。。。。
#2
不懂汇编,牛人.
#3
in跟pos的应用范围不一样,硬拿他们比较没有意义
#4
不是比较,是弄清楚编译器实现in的本质。
#5
#6
来句庸俗的."华丽的插入前十!"
#7
#8
我是个菜鸟 Delphi是开发语言还是开发环境啊
#9
我只是路过看看的。
#10
当范围小的时候应该会更快,比如如果是 in [0..7],后面那个 set 常量只会占用一个字节
#11
支持一下!
#12
如果是直接死值那么的确是占用更小
但如果是使用我上面那个函数
function AnsiStrInCharSet(ch: char; CharSet: TSysCharSet): boolean;
begin
Result := ch in CharSet;
end;
那么
AnsiStrInCharSet(‘’,[0..n])这种方式的话是一样的,那个常量还是32byte
#13
上面说错了,如果是直接死值那么in的实现方式又是另一种,不使用bt指令所以不存在那个常量值
#14
中国很少有用DELPHI
#15
相信Delphi能再造辉煌。顶顶顶顶顶!
#16
这个是什么,好复杂啊
#17
#18
好帖。
#19
支持一下!
#20
晕,没看懂~
#21
#22
回帖有分拿、、、
#23
虽然看不懂,还是顶顶,赚分吧
#24
学习学习
#25
#26
#27
学习学习 顶顶
#28
顶你!~~!
#29
谢谢~~!
#30
..............
#31
不错 不错 非常不错 哈哈
#32
我相信你是分析完了, 但是你的写法只会让初学的人一头雾水. 建议这样的文章应该写的通俗易懂些, 才能给大家分享
#33
楼上说的很有道理,我就是初学者!
#34
我还能看得懂,就是排版比较凌乱。
#35
啊三是事实是事实是事实是事实是事实是事实是事实是事实收拾收拾
#36
学习!!!
#37
学习学习
#38
#39
#40
讲得太深了
#41
来句庸俗的."华丽的插入前十!"
#42
每天回帖即可获得10分可用分!
#43
每天回帖即可获得10分可用分!
#44
每天回帖即可获得10分可用分!
#45
其实,我想要5分,下载 CFS 视频破解器。。给我分吧
#46
不懂汇编
#47
学习支持那份
#48
好好。。。。。。。
#49
每天回帖即可获得10分可用分!
#50
是很好的东西!!!1