【问题标题】:Why does my code print a repeated garbage character after my string?为什么我的代码在我的字符串后打印一个重复的垃圾字符?
【发布时间】:2020-01-01 20:51:01
【问题描述】:

您好,我是Assembly 的新手,我在练习中遇到了一些问题,要求我在原始字符串中查找子字符串,如果找到,则将其替换为另一个给定的字符串。

示例: original string = "这个字符串是字符串";

要查找的字符串 = "字符串"

字符串替换 = "dog"

输出="这条狗是狗"

void main()
{
    //Input

    char stringa[1024] = "This string is a string";

    char str1[] = "string"; // string to find

    char str2[] = "dog";    // string to replace

    // Output
    char risultato[1024]; 

    __asm
    {   

        LEA EDI, stringa
        MOV EAX, EDI             //EAX like 'i' in stringa
        LEA EDI, risultato
        MOV ECX, EDI         //ECX like 'j' in risultato

        //finding str1 in stringa
        MOV EDI, EAX
        LEA ESI, str1

 search:

        MOV BL, [ESI]       //current char of str1

        //if i'm at the end of str1 

                //mean that str1 is in stringa
        CMP BL, 0
        JZ found

        CMP[EDI], 0  //check if end of stringa
        JZ fine
        //otherwise
        CMP[EDI], BL
        JNE notfound
        INC EDI
        INC ESI
        JMP search


found:

        MOV EAX, EDI

        DEC EAX

        LEA ESI, str2   //sostitution of str1 with str2


sostituisci:

        MOV BL, [ESI]   //current char of str2

        CMP BL, 0   //checj the end of str2

        JZ continua

        //otherwise

        MOV EDI, ECX

        MOV [EDI], BL   //str2 paste in risultato
        INC ECX
        INC ESI
        JMP sostituisci //next position in str2

notfound:

        MOV EDI, EAX
        MOV ESI, ECX
        MOV BL, [EDI]
        MOV [ESI], BL
        INC ECX

continua:

        LEA ESI, str1
        INC EAX
        MOV EDI, EAX
        CMP [EDI], 0
        JNE search

fine:




    }

    // output
    printf("New string: %s\n", risultato);
}

我不明白为什么我的代码不能正常工作。 输出是:

新字符串:这条狗是狗╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠狗

而不是New string: This dog is a dog.

这些符号的原因是什么?

【问题讨论】:

  • 大概你忘了在你的char[]缓冲区的正确位置放置一个0字节作为终止符来标记隐式长度C字符串的结尾。在调试模式下,MSVC 使用0xCC 字节毒化堆栈;大概 是那个字节的字符。这使得调试函数更容易,因为错误比可能包含一些零字节的随机垃圾更明显。无论如何,使用调试器。
  • 您可以看到如何检查源字符串中的零。您可以找到这个零,因为在 C 和 C++ 中,当您执行 char str2[] = "dog"; 之类的操作时,从 "dog" 编译的初始值是四个字节长,三个字节代表字母,第四个字节为零。这就是为什么您在 C 的输入字符串中搜索零的原因。但是在新字符串中你没有在末尾写零 = 字符串不是以零结尾的 = 它不是有效的 C 字符串。
  • 完美,谢谢。我试图把 0 a 放在最后,但没有任何改变。出于这个原因,我认为我的代码中还有其他错误。可能我没有把它放在正确的位置。
  • @sof23 在调试器中使用内存视图以单个字节值的形式查看自己的内存内容。在单步执行每条指令时使用此视图,然后您可以观察在每次写入内存指令后如何逐字节构建结果字符串。然后,如果您确实尝试添加零(可能在fine: 标签之后),您应该在新字符串之后在内存中看到这个零字节。也许您有其他逻辑错误导致您无法正确检测到任务结束,或者您确实将零意外写入源字符串之一而不是结果字符串,...调试器有帮助:)
  • 尝试使用 "\0" 而不是 0 : "This string is a string\0".

标签: string assembly visual-c++ x86 inline-assembly


【解决方案1】:

不确定您的汇编程序为这个模棱两可的CMP [EDI], 0 编码了什么。确保它是一个字节大小的操作。也许你需要写cmp byte ptr [edi], 0之类的东西。


虽然您的程序有一个混乱的流程,但它会做它需要做的事情,除了在结果文本的末尾放置一个零终止符。

只需添加一条指令:

fine:
    mov byte ptr [ecx], 0

请注意,您可以使用任何通用寄存器来寻址内存,例如我使用的[ecx]

1.

    LEA EDI, stringa
    MOV EAX, EDI         //EAX like 'i' in stringa
    LEA EDI, risultato
    MOV ECX, EDI         //ECX like 'j' in risultato

变成:

    LEA EAX, stringa     //EAX like 'i' in stringa
    LEA ECX, risultato   //ECX like 'j' in risultato

2.

    MOV EDI, ECX
    MOV [EDI], BL   //str2 paste in risultato
    INC ECX

变成:

    MOV [ECX], BL   //str2 paste in risultato
    INC ECX

3.

notfound:
    MOV EDI, EAX
    MOV ESI, ECX
    MOV BL, [EDI]
    MOV [ESI], BL

变成:

notfound:
    MOV BL, [EAX]
    MOV [ECX], BL

LEA 指令可以为你做一些算术:

    MOV EAX, EDI
    DEC EAX

变成:

    LEA EAX, [EDI-1]

【讨论】:

  • MSVC 的内联汇编将模棱两可的 CMP [EDI], 0 编码为 CMP byte ptr [EDI], 0 。如果您尝试比较的值大于一个字节可以表示的值,它会截断该值并且不会警告您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-15
  • 1970-01-01
相关资源
最近更新 更多