Kro*_*ica 18 delphi delphi-7 delphi-xe5
我正在尝试将我当前的Delphi 7 Win32代码转换为Delphi XE5 Android,只需要很少的更改,这样我的项目就可以从一系列Delphi版本和XE5的Android交叉编译到Win32.
从XE5开始,针对未来的语言会发生重大变化.其中一个变化是从零开始的字符串.
在具有基于1的字符串的旧版本中,以下代码是正确的:
function StripColor(aText: string): string;
begin
for I := 1 to Length(aText) do
Run Code Online (Sandbox Code Playgroud)
但现在这显然不对.建议的解决方案是使用:
for I := Low(aText) to High(aText) do
Run Code Online (Sandbox Code Playgroud)
这样,XE5 Win32处理基于1的字符串,而XE5 Android处理基于0的字符串.但是有一个问题 - 以前的Delphi版本(例如XE2)在这样的代码上输出错误:
E2198 Low cannot be applied to a long string
E2198 High cannot be applied to a long string
Run Code Online (Sandbox Code Playgroud)
我有很多字符串操作代码.我的问题是 - 如何修改和保持上面的代码可以在Delphi 7 Win32和Delphi XE5 Android中编译?
PS我知道我仍然可以在XE5中禁用ZEROBASEDSTRINGS定义,但这是不受欢迎的解决方案,因为在XE6中,这个定义可能会消失,并且所有字符串都将被强制为0.
如果要支持使用基于一个字符串的版本,请不要定义ZEROBASEDSTRINGS
.这是有条件的目的.
没有迹象表明我知道条件将很快被删除.它是在XE3中引入的,并且在随后的两个版本中幸存下来.如果Embarcadero删除它,他们的Win32客户都不会升级,他们将破产.Embarcadero拥有保持兼容性的记录.您仍然可以使用TP对象和短字符串.只要桌面编译器可以使用,就可以使用此条件.
实际上,所有证据都指向移动编译器保留对基于一个字符串索引的支持.所有实用程序字符串函数都Pos
使用一个基于索引,并将继续这样做.如果Embarcadero真的要删除对基于一个字符串索引的支持,他们也将删除Pos
.我不相信这很快就会发生.
尽管编写返回字符串的低和高索引的函数是微不足道的.您只需IFDEF
在编译器版本上使用.
function StrLow(const S: string): Integer; inline;
begin
Result := {$IFDEF XE3UP}low(S){$ELSE}1{$ENDIF}
end;
function StrHigh(const S: string): Integer; inline;
begin
Result := {$IFDEF XE3UP}high(S){$ELSE}Length(S){$ENDIF}
end;
Run Code Online (Sandbox Code Playgroud)
更新
正如雷米指出的那样,上面的代码并不好.那是因为ZEROBASEDSTRINGS
是本地的,重要的是它在使用这些功能的地方的状态.事实上,以有意义的方式实现这些功能是不可能的.
因此,我认为对于需要使用传统编译器以及移动编译器进行编译的代码,您别无选择,只能禁用.ZEROBASEDSTRINGS
.
这是两个答案的总结:
正如 Remy Lebeau 所指出的,ZEROBASEDSTRINGS
是每个块的条件。这意味着以下代码将无法按预期工作:
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;
Run Code Online (Sandbox Code Playgroud)
有两种可能的解决方案:
答:每次有字符串项访问或迭代时IFDEF
,都会在其周围放置一个,这确实会让代码变得很混乱,但无论如何ZEROBASEDSTRINGS
设置它都会正常工作:
for I := {$IFDEF XE3UP}Low(aText){$ELSE}1{$ENDIF} to {$IFDEF XE3UP}High(aText){$ELSE}Length(aText){$ENDIF} do
Run Code Online (Sandbox Code Playgroud)
B. 由于ZEROBASEDSTRINGS
条件是per-block
它永远不会被第 3 方代码破坏,如果您不在代码中更改它,那就没问题(StringLow
只要调用者代码具有相同的ZEROBASEDSTRINGS
设置,上述内容就可以正常工作)。请注意,如果目标是移动设备,则不应ZEROBASEDSTRINGS OFF
在代码中全局应用,因为 RTL 函数(例如TStringHelper
)将返回基于 0 的结果,因为移动 RTL 是使用ZEROBASEDSTRINGS ON
.
附带说明- 有人可能建议Low/High
为旧版本的 Delphi 编写一个重载版本,但随后Low(other type)
(其中类型是某种数组)停止工作。看起来好像自从Low/High
不是常用的函数,那么就不能那么简单地重载。
TL;DR - 使用自定义StringLow
并且不要更改ZEROBASEDSTRINGS
代码。
归档时间: |
|
查看次数: |
3882 次 |
最近记录: |