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.
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?
ReplyDeleteMy gut feeling says it's the lack of "packed" in the declaration of the record, ie "TRec = packed record".
ReplyDeleteThat 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.
ReplyDeleteAsbjø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 ?
ReplyDeleteRichard 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.
ReplyDeleteMy gut feeling was wrong. The issue is that WriteLn(LRec2.Proc) silently assumes Proc is a zero-terminated string.
ReplyDeleteThat said, you should specify packed for records you do IO on.
ReplyDeleteHere's the proof btw:
ReplyDeletetype
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.
Asbjørn Heid Once again I agree with you just saying that it is not the end of world.
ReplyDeleteLook 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.
Asbjørn Heid Hey convert that into TStreamWriter! Just kidding.
ReplyDeleteAsbjø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.
ReplyDeleteBtw this is an artifact of WriteLn, if you for example do
ReplyDeleteprocedure print(const s: string);
begin
WriteLn(s);
end;
...
Print(r[0].c);
in my example above, it will correctly print just 12.
A side note, you can write procedures to files, but this is not a trivial task.
ReplyDeleteWhat was your aim?
I just wanted to see if it was possible. How do you write a procedure to a file?
ReplyDeleteYou need the real pointer (starting point: TMethod record) and write bytes until you reach the RET instruction.
ReplyDeleteBut 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.
I was already considering to learn an assembly language.
ReplyDelete