User Changes Trunk

From Lazarus wiki
Jump to navigationJump to search

About this page

Below you can find a list of intentional changes since the the previous release not yet scheduled for inclusion in the next fixes release which can change the behaviour of previously working code, along with why these changes were performed and how you can adapt your code if you are affected by them.

All systems

Alignment of record variables

  • Old behaviour: Variables of record types (not just their fields, but the records as a whole when declared as independent variables) would be aligned at most to the maximum alignment of their fields, limited by the maximum field alignment set for the target. This same limit was used to determine padding of the record size.
  • New behaviour: Variables of record types are now always aligned inside stack frames or as global variables in a way which provides optimal alignment for their embedded fields, regardless of the used packrecords setting. Moreover, unpacked records are also padded up to a size which is a multiple of this alignment (to also provide optimal alignment inside arrays of such records). The alignment of record fields inside other records obviously only depends on the packing settings of the "parent" record.
  • Example:

<delphi> type

 tr = packed record
   d: double;
   b: byte;
 end;

</delphi> tr used to be aligned to 1 byte in stack frames and as global variable. Now it will be aligned to the native alignment of double (4 or 8 bytes depending on the target platform, limited by the maximum global/local alignment settings). Its size will remain 9 bytes as before (because of the packed specifier).

  • Reason: Performance.
  • Effect: The size of some non-packed records may change compared to previous versions. Other than that, the different alignment rules cannot impact your code unless you are making unsupported assumptions (like taking the address of a local variable, adding some value to it, and expecting that you are now pointing at the next local variable).
  • Remedy: If you depend on the layout and/or size of a record staying the same, always declare it as packed. Non-packed records are free to be changed by the compiler in any way that it sees fit (except for changing the types or order of the fields).

Byte/Word/Long/Qwordbool types

  • Old behaviour: Assigning "true" to variables of these types resulted in these variables getting the value "1". Typecasting ordinal values to Byte/Word/Long/Qwordbool also mapped these values onto [0,1].
  • New behaviour: Assigning true to such variables now sets them to "-1" (i.e., all 1 bits). Typecasting an ordinal value to such a type now leaves that ordinal value untouched.
  • Example:

<delphi> var

 b: byte;
 bb: bytebool;

begin

 bb:=true;
 writeln(ord(bb));
 b:=3;
 writeln(byte(wordbool(b)));

end. </delphi> This program used to print 1 in both cases, now it prints -1 for the first statement and 3 for the second.

  • Reason: Delphi-compatibility, compatibility with WinAPI functions. See http://bugs.freepascal.org/view.php?id=10233 for more information.
  • Effect: Code assuming that assigning true to a Byte/Word/Long/Qwordbool variable or parameter results in assigning the ordinal value "1" no longer works. This may affect e.g. translations of C headers where certain int parameters which function basically as boolean parameters were replaced with longbool.
  • Remedy: If you depend on the the ordinal value of a particular variable being 1, either use an expression such as longbool(1) (which can also be used in the declaration of a constant), or use a regular ordinal type rather than one of the *bool types.