So I was fiddling abit with reading from and writing to files. As can be seen, I got some garbage values on the end of the text from the file, and even if the file remains unchanged, the garbage does.


So I was fiddling abit with reading from and writing to files. As can be seen, I got some garbage values on the end of the text from the file, and even if the file remains unchanged, the garbage does.

I found it curious, and couldn't figure out why it happened. It doesn't happen, when the text written to the file has a length that is strictly smaller than the size of the Char array.

Does anyone know why this happens?

PS: If you are wondering about the name "Proc", then it was because I tried to write a procedure to a file, wondering if it was possible. Hint: It wasn't.

Comments

  1. If you examine the output in a hex editor, what are the values of the garbage at the end? Is it consistently one character (ie how many bytes?), and consistently one of the three visible values?

    ReplyDelete
  2. My gut feeling says it's the lack of "packed" in the declaration of the record, ie "TRec = packed record".

    ReplyDelete
  3. That being said, the old-school AssignFile and such is so outdated. I would go for something more modern, TStream-based with explicit encoding, say TStreamWriter.

    ReplyDelete
  4. Asbjørn Heid agreed it is the old school but it is still pretty simple to use for text files.  That being said, I ran your sample and ended up with 012"" on all 10 items but I saw funky characters on yours, are you expecting it to be empty ?

    ReplyDelete
  5. Richard Baroniunas It's not simpler than using TStreamWriter (they're about equal), and if you use TStreamWriter then you're significantly more future proof. What if you one day don't want to write to a file but to an in-memory object as part of a http response? With TStreamWriter you just change a couple of lines, no need to go over all the code.

    ReplyDelete
  6. My gut feeling was wrong. The issue is that WriteLn(LRec2.Proc) silently assumes Proc is a zero-terminated string.

    ReplyDelete
  7. That said, you should specify packed for records you do IO on.

    ReplyDelete
  8. Here's the proof btw:

    type
      TRec = record
        c: array[0..1] of char;
      end;
    var
      r: array[0..1] of TRec;
    begin
      r[0].c[0] := '1';
      r[0].c[1] := '2';
      r[1].c[0] := '3';
      r[1].c[1] := #0;
      WriteLn('"', r[0].c, '"'); // prints "123"
      Readln;
    end.

    ReplyDelete
  9. Asbjørn Heid Once again I agree with you just saying that it is not the end of world.

    Look at this link for a quick rewrite using TStreamWriter.

    http://stackoverflow.com/questions/13306752/text-file-writing-performances-in-delphi

    See if the similar happens and take it from there.

    ReplyDelete
  10. Asbjørn Heid Hey convert that into TStreamWriter!  Just kidding.

    ReplyDelete
  11. Asbjørn Heid is correct. Try defining Proc as array[0..3] and fill it with '0123'. Your results will be the output string 0123 + a funky character. If you check the file itself with something like Notepad++, it contains the character string correctly and also in my case tells me it's a UCS-2 Little Endian file. Finally, after reading the file into LRec2 I added LRec2.Proc[3] := #0. It now outputs 012 with no funky characters.

    ReplyDelete
  12. Btw this is an artifact of WriteLn, if you for example do

    procedure print(const s: string);
    begin
      WriteLn(s);
    end;

    ...
      Print(r[0].c);


    in my example above, it will correctly print just 12.

    ReplyDelete
  13. A side note, you can write procedures to files, but this is not a trivial task.
    What was your aim?

    ReplyDelete
  14. I just wanted to see if it was possible. How do you write a procedure to a file?

    ReplyDelete
  15. You need the real pointer (starting point: TMethod record) and write bytes until you reach the RET instruction.
    But as I said, without going into great detail, it is not a trivial task to predict the real end of a procedure on a binary level.

    On loading you need to relocate and adjust jump and call instructions.
    So some degree of Assembler knowledge is needed here.

    ReplyDelete
  16. I was already considering to learn an assembly language.

    ReplyDelete

Post a Comment