Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2013-03

LongString does not work?

16 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Xiangrong Fang

Hi All,

This does not work:

  TConfiguration = record
    DataFolder: string[MaxPathLen];
  end

Error: string length must be a value from 1 to 255

I already have this on the top of my uinit file: {$mode objfpc}{$H+}{$LONGSTRINGS ON}

Working with Lazarus 1.0.6/FPC2.6.0 on Linux 3.5/x86_64

Any hint please? Thanks!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130303/69f19f3a/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang
Xiangrong Fang wrote 16 lines
Hi All, This does not work: TConfiguration = record DataFolder: string[MaxPathLen]; end Error: string length must be a value from 1 to 255 I already have this on the top of my uinit file: {$mode objfpc}{$H+}{$LONGSTRINGS ON} Working with Lazarus 1.0.6/FPC2.6.0 on Linux 3.5/x86_64 Any hint please? Thanks!

The "String[...]" declaration always declares a ShortString and those can have only 1 to 255 characters. An AnsiString does not need the "[...]", because it has always variable length.

Side note: {$H+} and {$LONGSTRINGS ON} is redundant, both mean the same (though {$H+} is more commonly used).

Regards,
Sven

Reply by email

Xiangrong Fang
to Sven Barth

Ok, My purpose is to write the record into stream, so I cannot use variable length. Now I use an array [0..MaxPathLen] of Char.

2013/3/3 Sven Barth

Show quoted text 37 lines
On 03.03.2013 09:35, Xiangrong Fang wrote: > Hi All, > > This does not work: > > TConfiguration = record > DataFolder: string[MaxPathLen]; > end > > Error: string length must be a value from 1 to 255 > > I already have this on the top of my uinit file: {$mode > objfpc}{$H+}{$LONGSTRINGS ON} > > Working with Lazarus 1.0.6/FPC2.6.0 on Linux 3.5/x86_64 > > Any hint please? Thanks! > The "String[...]" declaration always declares a ShortString and those can have only 1 to 255 characters. An AnsiString does not need the "[...]", because it has always variable length. Side note: {$H+} and {$LONGSTRINGS ON} is redundant, both mean the same (though {$H+} is more commonly used). Regards, Sven -- ______________________________**_________________ Lazarus mailing list .**freepascal.org http://lists.lazarus.**freepascal.org/mailman/**listinfo/lazarus<http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130303/113d1a0c/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang
Xiangrong Fang wrote
Ok, My purpose is to write the record into stream, so I cannot use variable length. Now I use an array [0..MaxPathLen] of Char.

If you want to write a complete record to stream (and not write it's elements manually) you should declare your record as "packed" as only then the records are guaranteed to be the same on different plattforms (with the exception of different endianess).

E.g.

=== code begin ===

type
   TConfiguration = packed record
     //
   end;

=== code end ===

See also here: http://community.freepascal.org/docs-html/ref/refsu15.html

Regards,
Sven

Reply by email

Xiangrong Fang
to Sven Barth

Hi Sven,

{$mode objfpc}{$H+}
  TConfiguration = packed record
      DataFolder: string;
  end;

does not work, but:

  TConfiguration = packed record
      DataFolder: array [0..MaxPathLen] of Char;
  end;

worked. My save procedure is:

function SaveParams(var Buffer; Count: Integer; FileName: string): Boolean;
var
  fs: TFileStream;
begin
  Result := False;
  if not ForceDirectories(ExtractFilePath(FileName)) then Exit;
  try
    fs := TFileStream.Create(FileName, fmCreate);
    try
      fs.Write(Buffer, Count);
      Result := True;
    finally
      fs.Free;
    end;
  except
  end;
end;

It is called on the finalization section of config.pas:

SaveParams(cfg, SizeOf(cfg), cfn);
//cfg is TConfgiruation, cfn is the filename.

The symptoms of error are:
1. The DataFolder value is not saved to configuration file, although file saving seems succeeded.
2. There are weird access violations, e.g. on exiting or on occasions that I try to manipulate the configuration at runtime (RunError(203) was reported).

Anything that I did wrong? or, AnsiString is not supported this way anyway?

2013/3/3 Sven Barth

Show quoted text 35 lines
On 03.03.2013 10:57, Xiangrong Fang wrote: > Ok, My purpose is to write the record into stream, so I cannot use > variable length. Now I use an array [0..MaxPathLen] of Char. > If you want to write a complete record to stream (and not write it's elements manually) you should declare your record as "packed" as only then the records are guaranteed to be the same on different plattforms (with the exception of different endianess). E.g. === code begin === type TConfiguration = packed record // end; === code end === See also here: http://community.freepascal.** org/docs-html/ref/refsu15.html<http://community.freepascal.org/docs-html/ref/refsu15.html> Regards, Sven -- ______________________________**_________________ Lazarus mailing list .**freepascal.org http://lists.lazarus.**freepascal.org/mailman/**listinfo/lazarus<http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130303/5a709c84/attachment.html>

Reply by email

Jürgen Hestermann
to Xiangrong Fang
Xiangrong Fang wrote 6 lines
Hi Sven, {$mode objfpc}{$H+} TConfiguration = packed record DataFolder: string; end; does not work, but:

A (Ansi)string in {$H+} mode is just a pointer (to the characters of the string). So sizeof(DataFolder)=4 (or 8) in all cases. There is no room for the string unless you configure it with SetLength(DataFolder,MaxPathLen). But even then the record does not store the characters. It only stores the pointer to the string:

DataFolder = pointer
DataFolder[1] = DataFolder^[1] = first character of the string.

There is an automatic dereferenciation that allows to write DataFolder[x] although the logic would require DataFolder^[1].

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130303/ea16d1fa/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang: {$mode objfpc}{$H+} TConfiguration = packed record DataFolder: string; end; does not…
Xiangrong Fang wrote 46 lines
Hi Sven, {$mode objfpc}{$H+} TConfiguration = packed record DataFolder: string; end; does not work, but: TConfiguration = packed record DataFolder: array [0..MaxPathLen] of Char; end; worked. My save procedure is: function SaveParams(var Buffer; Count: Integer; FileName: string): Boolean; var fs: TFileStream; begin Result := False; if not ForceDirectories(ExtractFilePath(FileName)) then Exit; try fs := TFileStream.Create(FileName, fmCreate); try fs.Write(Buffer, Count); Result := True; finally fs.Free; end; except end; end; It is called on the finalization section of config.pas: SaveParams(cfg, SizeOf(cfg), cfn); //cfg is TConfgiruation, cfn is the filename. The symptoms of error are: 1. The DataFolder value is not saved to configuration file, although file saving seems succeeded. 2. There are weird access violations, e.g. on exiting or on occasions that I try to manipulate the configuration at runtime (RunError(203) was reported). Anything that I did wrong? or, AnsiString is not supported this way anyway?

No, AnsiString is not supported in this way. As J?rgen wrote it's basically a pointer to the string data and not a static array of the string data. And the write and read procedures of TStream (but also the file I/O) will write the record's memory as is and thus the value of the pointer will be written in case of AnsiString.

Regards,
Sven

Reply by email

Xiangrong Fang
to Jürgen Hestermann: A (Ansi)string in {$H+} mode is just a pointer (to the characters of the string). So…

A (Ansi)string in {$H+} mode is just a pointer (to the characters of the string). So sizeof(DataFolder)=4 (or 8) in all cases. There is no room for the string unless

I guess this is the cause, but then there is no need to specify "packed" if I just use array of char.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130303/2b2d82b1/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang
Xiangrong Fang wrote 6 lines
A (Ansi)string in {$H+} mode is just a pointer (to the characters of the string). So sizeof(DataFolder)=4 (or 8) in all cases. There is no room for the string unless I guess this is the cause, but then there is no need to specify "packed" if I just use array of char.

The "packed" should always be used if you want to read/write data. Only then you can be sure that the memory layout of the record is correct. Otherwise padding bytes will be added. Consider the following record:

=== example begin ===

type
   TMyRecord = record
     b: Byte;
     i: LongInt;
     w: Word;
   end;

=== example end ===

The size of this record will be 12, because between b and i and after w padding bytes are added. While if you add "packed" the size will be 7 and the fields will directly follow after each other.

The memory layout of non-packed records is not guaranteed to stay the same between FPC versions! It could be for example that we find a bug in the code that generates the memory layout of a record and then suddenly you can no longer read in files that were written by a version of your program compiled with the older compiler. For "packed" there is the guarantee though that the layout will stay the same.

Regards,
Sven

Reply by email

Bart
to Xiangrong Fang: {$mode objfpc}{$H+} TConfiguration = packed record DataFolder: string; end; does not…
Xiangrong Fang wrote 29 lines
TConfiguration = packed record DataFolder: array [0..MaxPathLen] of Char; end; worked. My save procedure is: function SaveParams(var Buffer; Count: Integer; FileName: string): Boolean; var fs: TFileStream; begin Result := False; if not ForceDirectories(ExtractFilePath(FileName)) then Exit; try fs := TFileStream.Create(FileName, fmCreate); try fs.Write(Buffer, Count); Result := True; finally fs.Free; end; except end; end; It is called on the finalization section of config.pas: SaveParams(cfg, SizeOf(cfg), cfn); //cfg is TConfgiruation, cfn is the filename.

Are you only writing strings (and/or integers and/or booleans) to the configuration file?
If so, wouldn't it be just easier to use a TIniFile for that?

Bart

Reply by email

Xiangrong Fang
to Bart

I was using an INI file, but record make things a lot easier.

2013/3/3 Bart

Show quoted text 46 lines
On 3/3/13, Xiangrong Fang wrote: > TConfiguration = packed record > DataFolder: array [0..MaxPathLen] of Char; > end; > > worked. My save procedure is: > > function SaveParams(var Buffer; Count: Integer; FileName: string): Boolean; > var > fs: TFileStream; > begin > Result := False; > if not ForceDirectories(ExtractFilePath(FileName)) then Exit; > try > fs := TFileStream.Create(FileName, fmCreate); > try > fs.Write(Buffer, Count); > Result := True; > finally > fs.Free; > end; > except > end; > end; > > It is called on the finalization section of config.pas: > > SaveParams(cfg, SizeOf(cfg), cfn); > //cfg is TConfgiruation, cfn is the filename. > Are you only writing strings (and/or integers and/or booleans) to the configuration file? If so, wouldn't it be just easier to use a TIniFile for that? Bart -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130303/d5346522/attachment.html>

Reply by email

Luca Olivetti
to Sven Barth: The "packed" should always be used if you want to read/write data. Only then you can be…

Al 03/03/13 14:34, En/na Sven Barth ha escrit:

For "packed" there is the guarantee though that the layout will stay the same.

Are you sure? Does the same guarantee apply to bitpacked? Lately I've become lazy, and instead of manually decoding data (bits, bytes, words) read from a device, I'm relying on packed/bitpacked records, but I wasn't sure that upgrading the compiler wouldn't break my code.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es Tel. +34 935883004 Fax +34 935883007

Reply by email

Sven Barth
to Luca Olivetti
Luca Olivetti wrote 10 lines
Al 03/03/13 14:34, En/na Sven Barth ha escrit: > For "packed" there is the > guarantee though that the layout will stay the same. Are you sure? Does the same guarantee apply to bitpacked? Lately I've become lazy, and instead of manually decoding data (bits, bytes, words) read from a device, I'm relying on packed/bitpacked records, but I wasn't sure that upgrading the compiler wouldn't break my code.

For "packed" it is guaranteed (*), because this is the whole purpose of this modifier, for "bitpacked" it is not. It just tells the compiler to pack the record as densly as possible, but depending on the platform this might not be possible.

(*) the only exception for this is the JVM platform, because there the
file I/O mechanism of Pascal is not supported

Regards,
Sven

Reply by email

Luca Olivetti
to Sven Barth

Al 03/03/13 21:52, En/na Sven Barth ha escrit:

Show quoted text 16 lines
On 03.03.2013 20:32, Luca Olivetti wrote: > Al 03/03/13 14:34, En/na Sven Barth ha escrit: > >> For "packed" there is the >> guarantee though that the layout will stay the same. > > Are you sure? Does the same guarantee apply to bitpacked? > Lately I've become lazy, and instead of manually decoding data (bits, > bytes, words) read from a device, I'm relying on packed/bitpacked > records, but I wasn't sure that upgrading the compiler wouldn't break my > code. For "packed" it is guaranteed (*), because this is the whole purpose of this modifier, for "bitpacked" it is not. It just tells the compiler to pack the record as densly as possible, but depending on the platform this might not be possible.

At the moment I don't care about the platform, only about different (newer) versions of the compiler.
Currently , with 2.6.0, bitpacked under win32 gives me the correct layout (I have to adjust endianness for words/dwords but individual bit fields are where they should be).
Can I be sure that 2.6.2 (and later version) won't break my code?

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es Tel. +34 935883004 Fax +34 935883007

Reply by email

Sven Barth
to Luca Olivetti
Luca Olivetti wrote 21 lines
Al 03/03/13 21:52, En/na Sven Barth ha escrit: > On 03.03.2013 20:32, Luca Olivetti wrote: >> Al 03/03/13 14:34, En/na Sven Barth ha escrit: >> >>> For "packed" there is the >>> guarantee though that the layout will stay the same. >> Are you sure? Does the same guarantee apply to bitpacked? >> Lately I've become lazy, and instead of manually decoding data (bits, >> bytes, words) read from a device, I'm relying on packed/bitpacked >> records, but I wasn't sure that upgrading the compiler wouldn't break my >> code. > For "packed" it is guaranteed (*), because this is the whole purpose of > this modifier, for "bitpacked" it is not. It just tells the compiler to > pack the record as densly as possible, but depending on the platform > this might not be possible. At the moment I don't care about the platform, only about different (newer) versions of the compiler. Currently , with 2.6.0, bitpacked under win32 gives me the correct layout (I have to adjust endianness for words/dwords but individual bit fields are where they should be). Can I be sure that 2.6.2 (and later version) won't break my code?

I can only give you a guarantee for packed. For bitpacked it's documented that you shouldn't rely on the binary format.

Regards,
Sven

Reply by email