【问题标题】:flip line order assembly 32bit翻转线订单汇编 32bit
【发布时间】:2018-05-06 18:31:27
【问题描述】:

我需要翻转文件的行顺序并将它们写入另一个文件,但我有一些问题。由于某种原因我无法在 file2 中写入...任何建议和提示都会很有用,这是我的第一个问题这种类型的。我老师的一个提示是使用 fseek,我使用了它,但我卡住了。

示例:

输入文件1:

line1
line 2
line 3

所需的输出文件2:

line 3
line2
line 1

    .386
    .model flat, stdcall
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;includem biblioteci, si declaram ce functii vrem sa importam
    includelib msvcrt.lib
    extern exit: proc
    extern fopen:proc
    extern getc:proc
    extern fclose:proc
    extern printf:proc
    extern ftell:proc
    extern fseek:proc
    extern fscanf:proc
    extern fprintf: proc
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;declaram simbolul start ca public - de acolo incepe executia
    public start
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ;sectiunile programului, date, respectiv cod
    .data
    ;aici declaram date
    s db 99 dup(0)
    read db "r",0
    write db "w",0
    nume db "fisier1.txt",0
    nume2 db "fisier2.txt",0
    seek_end dd 2
    format db "%s",0
    .code

    start:
        ;open first file to read
        push offset read
        push offset nume
        call fopen
        add esp,8
        mov esi,eax;save pointer of file

        ;open second file to write
        push offset write
        push offset nume2
        call fopen
        add esp,8
        mov edi,eax;save pointer of file

        ;find the end of file
        push seek_end
        push -1
        push esi
        call fseek
        add esp,12

        ;save in ecx current position
        push esi
        call ftell
        add esp,4
        mov ecx,eax

        et:
            push esi
            call getc
            add esp,4
            cmp eax,0ah;verify if isn't new line
            jne previous
            previous:
                ;move to the previous line
                push 1
                push -1
                push esi
                call fseek
                add esp,12
                jmp cont
            read_write:
                ;read the line in string s 
                push offset s
                push offset format
                push esi
                call fscanf
                add esp,12

                ;print string s in second file
                push offset s
                push offset format
                push edi
                call fprintf
                add esp,12

                jmp previous

        cont:
            dec ecx
            ;verify if isn't the beginning of file  
            cmp ecx,0
            jne et

        push 0
        call exit
    end start

【问题讨论】:

  • 那么当你运行这个程序时会发生什么? fisier2.txt 是由您的第二个 fopen 函数调用创建的,对吗?然后你寻找输入文件的输入并尝试从那里读取,返回 EOF 因为你在最后。此外,ECX 是您正在使用的调用约定中的一个调用破坏寄存器,因此希望每个库 call 销毁它。使用ebx 作为您的柜台或其他东西。无论如何,这不是minimal reproducible example,因为您还没有展示会发生什么。 idownvotedbecau.se/nodebugging
  • 您的老师使用lseek 的提示可能是使用它来查找文件的长度以找出您需要多大的缓冲区,然后回到开头。然后读取整个输入文件,并在缓冲区上向后循环,找到换行符时打印行。
  • 对不起,老师的提示是 fseek,文件创建成功,从 file1 读取没问题,但由于某种原因写入 file2 不起作用
  • fseek 更有意义,因为您正在使用其他 C stdio 函数,并且 fseek 到末尾 + ftell 是查找文件长度的唯一 ISO C 方法。但是不要忘记fseek 回到开头。如果您有lseek 可用,您将使用statfstat。无论如何,使用调试器来找出在您单步执行程序时会发生什么,哪些函数成功,哪些返回错误。
  • 你在为什么操作系统编程?

标签: assembly x86 masm masm32


【解决方案1】:

这绝对是我不会用汇编语言编写的……但是,要完成这项工作,我会首先用高级语言编写算法。如果您可以使逻辑在更高级别的语言中正常工作,那么您就可以使您的汇编工作。

in = fopen("source.txt", "r");
fseek(in, 0, SEEK_END);
size = ftell(in);
fseek(in, 0, SEEK_SET);
out = fopen("destination.txt", "w");
ftruncate(out, size);
fseek(out, 0, SEEK_END);
while(fgets(buf, sizeof(buf), in))
{
    len = strlen(buf);
    fseek(out, -len, SEEK_CUR);
    fwrite(out, 1, len, buf);
    fseek(out, -len, SEEK_CUR);
}

此函数对sizeof(buf) 确定的行的大小有限制,并且该行存在错误:

如果fgets() 可以读取sizeof(buf) 字节,则它不会返回以空字符结尾的字符串。

不幸的是,这就是 C 库的糟糕程度。对该错误的简单修复:

buf[sizeof(buf) - 1] = '\0';
...
fgets(buf, sizeof(buf) - 1, in)

即您将'\0' 放在缓冲区的末尾,并且永远不要覆盖它。所以至少你永远不会超出你的缓冲区。

现在您可以在汇编中转换该 C 代码。

在进行实际编码之前,还要先了解你的算法。

注意:我也没有测试任何错误代码。错误处理是个好主意。 (即如果fopen("destination.txt"...) 失败怎么办?)

【讨论】:

  • 哦,是的,我想我们也可以利用输出文件作为常规文件的优势,并在其中查找。在有关问题的 cmets 中,我建议将整个输入文件读入内存并按顺序写入输出。太糟糕了fgets 不返回读取的字节数;这只是愚蠢的,这意味着你可以轻松地循环,直到你复制了整行。那么设计就会很奇怪,而不是错误。
  • @PeterCordes, fgets() 本身不是一个错误,但我敢肯定,使用它会产生无限数量的错误,如果它可以放一个'\0' 无论如何都是最后一个字符...至少他们在 C++ 中修复了这个问题(他们甚至删除了 '\n' 字符!)
  • 好吧,是的,不是错误,但它知道它读取了多少字节,并且只是选择返回其输入参数之一,同时丢弃有用的数据。这只是愚蠢的,所以如果你需要长度,你必须打电话给strlen。 C stdio 和字符串函数似乎经常丢弃有用的信息,就好像设计它们的人没有考虑 asm / 在同一数据上多次循环的效率。有时您不在乎,strcat 很方便,但有时您会这样做……无论如何,存储 \n 确实可以让您判断您是否阅读了整行,所以这很有用。
猜你喜欢
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-13
  • 1970-01-01
  • 2019-05-11
相关资源
最近更新 更多