zoukankan      html  css  js  c++  java
  • 汇编语言学习笔记(六)

    十八、字符串处理

    前文介绍过字符串的处理,字符串是byte类型 的数组,现在实现一段代码,将字符串string1数据copy到字符串string2中

    代码如下

        .data
    string1 byte "Hello World!", 0
    string2 byte 12 dup(?), 0
        .code
    mov ecx, 12
    mov ebx,0
    .repeat
    mov al, string1[ebx]
    mov string2[ebx], al
    inc ebx
    .untilcxz

    通过ecx递减,将字符串string1每个字符一次copy给string2中,其中用到了ebx基址寄存器。

     也可以通过esi和edi寄存器

        .data
    string1 byte "Hello World!"
    stirng2 byte 12 dup(?), 0
        .code
    mov ecx,12
    lea esi, string1
    lea edi, string2
    .repeat
    mov al,[esi]
    mov [edi],al
    inc edi
    inc esi
    .untilcxz

    这些代码可以通过字符串操作的其他指令替代,使代码更简洁

    1 movsb指令

    movsb是字符串移动指令,将esi指向的字符移动到edi指向的空间,并且将ecx减1,寄存器esi和edi内容增加1或者减少1

    如果仅仅使用movsb指令作用不大,配合循环使用,功能很强大。cld指令表示方向标志值清0,调用movsb会使esi和edi内容增加1

    std指令表示设置方向标志值,调用movsb会使esi和edi内容减少1

    还是上面的需求,这次使用movsb完成目标

    mov ecx,12                ; 字符串大小为12
    mov esi, offset string1   ; esi指向string1起始位置
    mov edi, offset string2   ; edi指向string2起始位置
    cld                       ; cld指令调用后 ,调用movsb会使esi和edi分别加1
    .repeat
     movsb                    ; 先将esi指向的空间数据拷贝到edi指向的空间
                              ; 然后esi和edi分别加1,并且ecx值减少1
    .untilcxz

    和movsb配合使用的几个前缀:

    rep   重复操作,等于循环,直到ecx为0退出循环

    repe  如果相等,则重复操作,如果不等,那么退出循环,或者ecx为0退出循环

    repne  不相等,则重复操作,相等则退出循环,或者ecx为0退出循环

    上面的代码可以使用 rep movsb更改,完成同样的目的

    mov ecx, 12
    lea esi, string1
    lea edi, string2
    cld
    rep movsb   ;循环直到ecx为0结束

    2  scasb指令

    scasb指令用于在edi寄存器指定的空间中搜寻al所存储的字符。scasb指令操作流程为:将要查询的字符放入al寄存器中,

    如果要在字符串string中查找匹配的字符,那么将edi存储string的首地址,调用scasb进行匹配,scasb指令调用后会将edi

    存储数值加1,并且ecx值-1,为了完成字符串string中逐个字符匹配,需要在scasb前面加上repne指令,这样在不相等时继续

    查找,直到查找到指定字符退出循环。此时edi指向的位置为字符串string中匹配字符位置的下一个位置。

    举例实现:

    .data
    name1  byte "Abe Lincoln"
    .code
    mov al, ' '                ; 在al寄存器中存储空格,为了在name1中查找该空格
    mov ecx, lengthof name1    ;ecx存储name1字符串长度,为11
    lea edi, name1             ;edi指向name1首地址
    repne scasb                ;匹配edi指向空间的字符和空格是否相等,不相等则edi加1
                               ;ecx减1,直到相等或者ecx为0退出循环

    运行后ecx为7,edi执行字符L的位置

    效果图如下:

    3  stosb指令

    stosb用于把寄存器al存储的数据放入寄存器edi所指向的空间,指令完成后edi增加1

    stosb等价于:

    mov [edi],al

    inc edi

    4  lodsb指令

    lodsb用于把寄存器esi所指向的空间数据存储到al寄存器中,指令完成后esi增加1

    lodsb等价于:

    mov al, [esi]

    inc esi

    下面实现将字符串姓名倒置功能,并将名字和姓中间添加字符“ ”和“,”

    如“Abe Lincoln”变为“Lincoln, Abe”

        .data
    name1 byte "Abe Lincoln"
    name2 byte 12 dup (?)
        .code
    mov al, ''
    mov ecx, lengthof name1
    lea edi, name1
    repne scasb
    push ecx
    mov esi, edi
    lea edi, name2
    rep movsb
    mov al, ' '
    stosb 
    mov al, ' '
    stosb
    mov ecx, lengthof name2
    pop eax
    sub ecx, eax
    dec ecx
    lea esi , name1
    rep movsb

    5  cmpsb指令

    字符串比较指令,该指令和movsb差不多,比较edi和esi指向空间数据大小,并且edi和esi增加1或者减少1,

    可通过cld或std设置,并且ecx减少1

    比较“James” 和 “James”

    代码如下:

    .data
    name1 byte "James"
    name2 byte "James"
    .code
    mov ecx, lengthof name1
    lea esi, name1
    lea edi, name2
    cld
    repe cmpsb

    相等情况下ecx为0,edi和esi都指向字符串最后一个字符的下一个位置

    如果比较的字符为“James”和“Jamie”,那么效果如下:

    如果比较字符为“Marci”和“Marcy”,那么上述代码就没办法区分是否相等了,因为此时ecx也为0

    如果ecx大于0,那么两个字符串肯定不相等的,如果ecx为0,那么将esi和edi都-1,得到最后一个元素,

    再将esi和edi指向空间的数据比较即可。

    下面将上述代码完善一下,比较两个长度相等的字符串name1和name2

    mov ecx, lengthof name1
    lea esi, name1
    lea edi, name2
    cld 
    repe cmpsb
    .if ecx > 0
    ;输出不相等
    .else 
      dec esi
      dec edi
      mov al, [esi]
      .if al != [edi]
       ; 输出不相等
      .else
        ;输出相等
      .endif
    .endif

    十九、字符串总结

    1  movsb 指令将寄存器esi指向的字节类型字符串的内容移动到寄存器edi指向的位置,通过cld或std设置esi和edi增加还是减少

    2  cmpsb 指令对寄存器的esi指向的字符串中的一个字符和edi所指向的一个字符进行比较,通过cld或std设置esi和edi增加还是减少

    3  movsb指令前边的rep前缀会让该指令重复执行,循环次数等于ecx的值,每一次循环ecx的值减1,直到为0停止。

    4  cmpsb指令前面的repe前缀的作用类似于rep前缀,当ecx为0是,停止执行指令。或者当esi和edi所指向的两个空间的字节内容不同,循环也会停止。

        repne当esi和edi所指向的两个空间的字节内容相同时,停止。

    5  scasb指令将一个字符串进行搜索,查找字符串中是否存在寄存器al中所存储的字符。如果找到该字符,那么edi指向的地址比该字符的地址靠后一个字节。

        stosb将al寄存器的内容存储在edi所指向的字符串的位置中。lodsb指令将把寄存器esi所指向的字符串的位置中的字符复制到al寄存器中。

    我的微信公众号,谢谢关注:

  • 相关阅读:
    第一篇阅读笔记
    课程信息管理系统
    HDU1124求n的阶乘后0的个数
    分解质因数算法
    牛客小白月赛23 B阶乘(质因数分解)
    JAVAWEB将图片铺满整个页面的方法
    Codeforces Global Round 7
    POJ--1703并查集(区分两个集合)
    POJ--1611经典并查集
    DFS,BFS回顾(各种题)(肺炎疫情中,祝平安)
  • 原文地址:https://www.cnblogs.com/secondtonone1/p/6710407.html
Copyright © 2011-2022 走看看