巧用位运算实现大小写转换
分类:Assembly
今天看王爽老师的《汇编语言》时,很有收获,不论是技术还是思考方式。
任务是将字符串进行大小写转换,但是还暂时不会用分支判断语句(而且这样的效率也不是最高的,有点类似于高级语言了)。
“如果一个问题的解决方法,使我们陷入一种矛盾之中。那么,很可能是我们考虑问题的出发点有了问题,或是说,我们起初运用的规律并不适合。”(强行被王老师灌了一碗鸡汤,爽!)
扯点淡:这两天正好遇到一点事情,使我略微开始怀疑自己,(当然也没那么严重,卓教授可是非常厉害的,承载了太多期许的目光,岂能轻言放弃。不能把世界交给我看不起的人!),所以王老师的这句话使我,换一种思考方式,也许会柳暗花明。
初步想法是,判断字符的ASCII码,如果大于61H,则减20H。但是没有判断语句,所以这条道走不通。
我们应该重新观察,寻找新的规律。可以看出,就ASCII码的二进制形式来看,除第5位(位数从0开始计算)外,大写字母和小写字母的其他各位都一样。大写字母ASCII码的第5位为0,小写字母的第5位为1。这样,我们就有了新的方法,一个字母,不管他原来是大写还是小写,将他的第5位置0,他就必将变为大写字母;将他的第5位置1,他就必将变为小写字母。在这个方法中,我们不需要在处理前判断字母的大小写。
果然,奇技淫巧...
代码如下:
assume cs:code, ds:data
data segment
db 'BaSiC'
db 'iNfOrMaTiOn'
data ends
code segment
start:
mov ax, data
mov ds, ax ;设置ds指向data段
mov bx, 0 ;设置(bx)=0,ds:bx指向'BaSiC'的第一个字母
mov cx, 5 ;设置循环次数
s1:
mov al, [bx] ;将ASCII码从ds:bx所指向的单元中取出
and al, 11011111B ;将al中的ASCII码的第5位置为0,变为大写字母
mov [bx], al ;将转变后的ASCII码写回原单元
inc bx ;(bx)加1,ds:bx指向下一个字母
loop s1
mov bx, 5 ;设置(bx)=5,ds:bx指向'iNfOrMaTiOn'的第一个字母
mov cx, 11 ;设置循环次数,因为'iNfOrMaTiOn'有11个字母
s2:
mov al, [bx]
or al, 00100000B ;将al中的ASCII码的第5位置为1,变为小写字母
mov [bx], al
inc bx
loop s2
mov ax, 4c00h
int 21h
code ends
end start
在以后的操作中,可以从更底层的角度看看能否通过位运算来实现,效率更高,结果更精准。
如果有收获,可以请我喝杯咖啡!