问题描述
我试图以最小的更改将当前的Delphi 7 Win32代码转换为Delphi XE5 Android,以便可以从一系列的Delphi版本和XE5的Android将项目交叉编译到Win32。
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 versions and Android from XE5.
从XE5开始,针对未来的语言发生了重大变化。此类更改之一是从零开始的字符串。
Starting from XE5 there are breaking changes in language aimed at future. One of such changes is zero-based strings.
在具有基于1的字符串的旧版本中,以下代码是正确的:
In older versions with 1-based strings the following code was correct:
function StripColor(aText: string): string;
begin
for I := 1 to Length(aText) do
但是现在这显然是不对的。建议的解决方案是使用:
but now this is obviously not right. Suggested solution is to use:
for I := Low(aText) to High(aText) do
这样XE5 Win32可以处理基于1的字符串,而XE5 Android可以正确处理基于0的字符串。但是存在一个问题-先前的Delphi版本(例如XE2)在此类代码上输出错误:
This way XE5 Win32 handles 1-based strings and XE5 Android handles 0-based strings right. However there's a problem - previous Delphi versions (e.g. XE2) output an error on such code:
E2198 Low cannot be applied to a long string
E2198 High cannot be applied to a long string
我有很多字符串操作代码。我的问题是-如何修改以上代码并使其在Delphi 7 Win32和Delphi XE5 Android中可编译?
I have quite a lot of string manipulation code. My question is - how to modify and keep above code to be compileable in Delphi 7 Win32 and Delphi XE5 Android?
P.S。我知道我仍然可以在XE5中禁用ZEROBASEDSTRINGS定义,但这是不希望的解决方案,因为在XE6中,该定义可能会消失,并且所有字符串都将被强制从0开始。
P.S. I know I can still disable ZEROBASEDSTRINGS define in XE5, but that is undesired solution since in XE6 this define will probably be gone and all strings will be forced to be 0-based.
推荐答案
这是两个答案的总和:
Remy Lebeau指出, ZEROBASEDSTRINGS
是每个块的条件。这意味着以下代码将无法按预期运行:
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;
有2种可能的解决方案:
There are 2 possible solutions:
一种。每次有字符串项访问或迭代时,在其周围放置一个 IFDEF
,这对于代码来说确实很混乱,但无论为何,它都能正常工作ZEROBASEDSTRINGS
的设置:
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。由于 ZEROBASEDSTRINGS
条件是每块
,因此它永远不会被第三方代码所破坏,如果您不更改它在您的代码中就可以了(只要调用者代码具有相同的 ZEROBASEDSTRINGS
设置,在 StringLow
以上就可以正常工作) 。请注意,如果目标是移动的,则由于RTL函数(例如 TStringHelper
),您不应在代码中全局应用 ZEROBASEDSTRINGS OFF
将返回基于0的结果,因为移动RTL是在 ZEROBASEDSTRINGS ON
启用的情况下编译的。
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
.
-对于较旧的Delphi版本,可能建议写 Low / High
的重载版本,但随后写 Low(其他类型)
(类型是某物的数组)停止工作。看起来由于 Low / High
不是常用函数,因此不能简单地重载。
On a side note - One might suggest to write an overloaded versions of Low/High
for older versions of Delp 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 -使用自定义 StringLow
,不要在代码中更改 ZEROBASEDSTRINGS
。
TL;DR - Use custom StringLow
and don't change ZEROBASEDSTRINGS
in your code.
这篇关于从Delphi XE5开始,如何以向后兼容的方式处理基于0的字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!