How to work with 0-based strings in a backwards compatible way since Delphi XE5?

后端 未结 5 931
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-07 04:18

I\'m trying to convert my current Delphi 7 Win32 code to Delphi XE5 Android with minimal changes, so that my project can be cross-compiled to Win32 from a range of Delphi versio

5条回答
  •  梦毁少年i
    2021-02-07 05:06

    This is rather a sum up of the two answers:

    As pointed out by Remy Lebeau, ZEROBASEDSTRINGS is a per-block conditional. That means that the following code will not work as expected:

    const
      s: string = 'test';
    
    function StringLow(const aString: string): Integer; inline; // <-- inline does not help
    begin
      {$IF CompilerVersion >= 24} 
      Result := Low(aString); // Delphi XE3 and up can use Low(s)
      {$ELSE}
      Result := 1;  // Delphi XE2 and below can't use Low(s), but don't have ZEROBASEDSTRINGS either
      {$ENDIF}
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      {$ZEROBASEDSTRINGS OFF}
      Memo1.Lines.Add(Low(s).ToString);        // 1
      Memo1.Lines.Add(StringLow(s).ToString);  // 1
      {$ZEROBASEDSTRINGS ON}
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      {$ZEROBASEDSTRINGS ON}
      Memo1.Lines.Add(Low(s).ToString);        // 0
      Memo1.Lines.Add(StringLow(s).ToString);  // 1  <-- Expected to be 0
      {$ZEROBASEDSTRINGS OFF}
    end;
    

    There are 2 possible solutions:

    A. Every time there's string items access or iteration place an IFDEF around it, which is indeed a lot of clutter for the code, but will work properly irregardless of ZEROBASEDSTRINGS setting around it:

    for I := {$IFDEF XE3UP}Low(aText){$ELSE}1{$ENDIF} to {$IFDEF XE3UP}High(aText){$ELSE}Length(aText){$ENDIF} do
    

    B. Since the ZEROBASEDSTRINGS conditional is per-block it never gets spoiled by 3rd party code and if you don't change it in your code you are fine (above StringLow will work fine as long as the caller code has the same ZEROBASEDSTRINGS setting). Note that if target is mobile, you should not apply ZEROBASEDSTRINGS OFF globally in your code since RTL functions (e.g. TStringHelper) will return 0-based results because mobile RTL is compiled with ZEROBASEDSTRINGS ON.

    On a side note - One might suggest to write an overloaded versions of Low/High for older versions of Delphi, but then Low(other type) (where type is array of something) stops working. It looks like since Low/High are not usual functions then can not be overloaded that simply.

    TL;DR - Use custom StringLow and don't change ZEROBASEDSTRINGS in your code.

提交回复
热议问题